Scala
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented Scala
-
Section 4: Functional Scala
-
Section 5: Collections in Depth
-
Section 6: Type System
-
Section 7: Concurrency and Ecosystem
-
Section 8: Practical Projects
-
Section 9: Interview Practice
-
Section 10: Data Structures and Algorithms in Scala
-
Section 11: More Practice Exercises
-
Section 12: Advanced Functional Patterns
-
Section 13: More Ecosystem
-
Section 14: Scala Collections Library Deep Dive
-
Section 15: Scala Standard Library Deep Dive
-
Section 16: Akka Ecosystem Deep Dive
-
Section 17: Cats and Cats Effect Deep Dive
-
Section 18: Play Framework Deep Dive
-
Section 19: Apache Spark with Scala Deep Dive
-
Section 20: Scala Build Tools Deep Dive
-
Section 21: Scala 3 Specific Features
-
90: Union and Intersection Types
-
Section 22: Scala Testing Deep Dive
-
Section 23: Functional Domain Modeling
-
Section 24: More Data Structures and Algorithms in Scala
-
Section 25: Scala for Data Engineering
-
Section 26: More Practical Projects
-
Section 27: More Interview and Review
-
Section 28: ZIO Ecosystem Deep Dive
-
Section 29: Scala for Machine Learning
-
Section 30: Scala Microservices Architecture
-
Section 31: Scala Type System Deep Dive
-
Section 32: More Practice and Drills
-
Section 33: Scala Performance Deep Dive
-
Section 34: Scala Ecosystem Tooling
-
Section 35: Scala for Reactive Systems
-
Section 36: More Real-World Case Studies
-
Section 37: Scala for Financial Systems
-
Section 38: Scala GraphQL and gRPC
-
Section 39: More Final Projects
-
Section 40: More Interview and Final Review
-
Section 41: Scala for Streaming Data
-
Section 42: Scala Security Practices
-
Section 43: More Language Deep Dive
-
Section 44: Scala Command-Line Tools
-
Section 45: Scala Documentation and Style
-
Section 46: Scala Dependency Management
-
Section 47: More Practical Backend Patterns
-
Section 48: Scala for Event-Driven Architecture
-
Section 49: More Practice Drills Round 2
-
Section 50: Scala Compiler Deep Dive
-
Section 51: Scala for Web Frontends
-
Section 52: More Data Engineering Practice
-
Section 53: Scala Observability
-
Section 54: More Advanced Practice Projects
-
Section 55: Scala for Legacy Java Integration
-
Section 56: More Testing Practice
-
Section 57: Final Mastery Review
-
Section 58: Scala History and Ecosystem Context
-
Section 59: More Concurrency Patterns
-
Section 60: Scala for Configuration Management
-
Section 61: More Domain Modeling Practice
186: Publishing Libraries to Maven Central
By now, you've probably written a few internal libraries that you copy-paste between projects. It works, but it's a nightmare to maintain. Once your code is stable and useful, the right move is to publish it to Maven Central. That way, anyone—including your future self—can just add a single line to their build.sbt and get to work.
For this lesson, we're going to publish a small utility I've been wanting: a CaseInsensitiveMap. It's a simple wrapper around a standard Scala Map that treats keys as case-insensitive. It's small enough to keep this focused, but concrete enough to show how the publishing pipeline actually behaves.
Defining the CaseInsensitiveMap utility
First, I'll set up the core logic. I want this to feel like a native Scala collection, so I'll implement it as a class that wraps a Map[String, V].
package com.mentormind.collections
class CaseInsensitiveMap[V] {
private val inner = scala.collection.mutable.Map.empty[String, V]
def put(key: String, value: V): Unit = {
inner.put(key.toLowerCase, value)
}
def get(key: String): Option[V] = {
inner.get(key.toLowerCase)
}
def contains(key: String): Boolean = {
inner.contains(key.toLowerCase)
}
}
I'm keeping it minimal here. In a production library, I'd probably make it implement scala.collection.Map, but for the sake of demonstrating the publishing process, this is plenty.
Configuring sbt for Sonatype and Maven Central
You can't just "upload" to Maven Central. You actually go through Sonatype's OSSRH (Open Source Software Repository Hosting). You'll need an account there, but the heavy lifting happens in your project/plugins.sbt. I'm using sbt-pgp because Maven Central requires every single artifact to be digitally signed. If you don't sign your jars, they'll be rejected immediately.
// project/plugins.sbt
addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.1.1")
```
Now, in the main build.sbt, I need to define the coordinates. This is the "address" of your library. If you pick a generic organization name, Sonatype will reject your request during the account setup phase, so I'm using a specific domain I own.
organization := "com.mentormind"
name := "case-insensitive-map"
version := "0.1.0"
scalaVersion := "2.13.12"
publishTo := Some("sonatype::ossrh:release")
The GPG signing stumble
Here is where I always trip up the first time. I ran sbt publish, and it failed with a massive stack trace complaining that it couldn't find a GPG key. I had GPG installed on my machine, but I hadn't actually created a key pair or told sbt where to find it.
I tried to bypass it by setting pgpSigningKey := None, but that's a trap. While that lets the build finish locally, the Sonatype servers will reject the upload the moment it hits their API. To fix this, I had to generate a key using gpg --full-generate-key and then export the public key to a keyserver so Sonatype can verify it.
Once the key was live, I added the passphrase to my ~/.sbt/1.0/plugins/pgp.conf (or passed it as a system property) so I didn't have to type it every single time I published. It's a tedious step, but it's the price of admission for the global ecosystem.
Pushing to the staging repository
Maven Central uses a "Staging Repository." Your code doesn't go live immediately. Instead, it goes into a temporary bucket where Sonatype's automated tools check for the GPG signature, the POM file, and the Javadoc.
I run sbt publish, and sbt handles the upload of the JAR, the POM, and the signature files. After that, I head over to the Sonatype Nexus UI, find my staging repository, and click "Close" and then "Release." Only then does the library actually propagate to the Maven Central mirrors. It usually takes a few hours before you can actually see it when searching via sbt.
📋 Practical Task
Exercise: Local Simulation of CaseInsensitiveMap Publishing
Since creating a Sonatype account takes a few days for approval, your task is to simulate the publishing pipeline locally. This ensures your build.sbt and project structure are correct before you attempt a real upload.
- Create a new Scala project and implement the
CaseInsensitiveMapclass as shown in the lesson. - Configure your
build.sbtwith the organization"com.yourname.practice"and version"0.1.0-SNAPSHOT". - Instead of publishing to Sonatype, run the command
sbt publishM2. This publishes the library to your local~/.m2/repositoryfolder. - Create a separate Scala project in a different directory. In its
build.sbt, add the library you just published:libraryDependencies += "com.yourname.practice" % "case-insensitive-map" % "0.1.0-SNAPSHOT" - Write a small main method in this second project that instantiates
CaseInsensitiveMap, puts a value under the key"Scala", and successfully retrieves it using the key"scala".
There are no comments for now.