Java
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented Java
-
Section 4: Collections Framework
-
Section 5: Exception Handling
-
Section 6: Generics
-
Section 7: Functional Java
-
Section 8: Concurrency
-
Section 9: I/O and NIO
-
Section 10: JVM Internals
-
Section 11: Modern Java Features
-
Section 12: Build Tools and Project Structure
-
Section 13: Testing
-
Section 14: Databases and Persistence
-
Section 15: Networking
-
Section 16: Design and Best Practices
-
Section 17: Reflection and Annotations
-
Section 18: Logging and Diagnostics
-
Section 19: Date, Time, and Internationalization
-
Section 20: Java Platform Module System
-
Section 21: Security in Java
-
Section 22: Advanced Collections and Data Structures
-
Section 23: More Concurrency Patterns
-
Section 24: Compression, Files, and System Integration
-
Section 25: GUI Programming
-
Section 26: Practical Projects
-
Section 27: Data Structures and Algorithms
-
Section 28: Interview and Algorithm Practice
-
Section 29: JSON and Data Interchange
-
Section 30: More Concurrency Utilities
-
Section 31: More Collections and Streams Practice
-
Section 32: More File and System Programming
-
Section 33: Standard Library Deep Dive
-
Section 34: More Practice and Drills
-
Section 35: More Testing and Quality
-
Section 36: More Design Patterns and Architecture
-
Section 37: Career and Ecosystem
-
Section 38: More OOP and Architecture Practice
-
Section 39: More Enterprise Concepts
-
Section 40: Advanced JavaFX
-
Section 41: More Interview Practice
118: Maven Plugins and Profiles
You've already got the hang of the basic Maven lifecycle, but in a real-world professional environment, you rarely have just one way of building your app. You've got your local machine, a QA server, and a production environment. They all need different settings—different database URLs, different logging levels, and different sets of checks. This is where Maven Profiles and Plugins come into play.
I'm going to show you how to set up a project that behaves differently depending on whether you're just hacking away locally or preparing a release for production. We'll build a simple configuration switcher and use a plugin to enforce code quality only during the production build.
Switching Environments with Profiles
First, let's talk about profiles. Think of a profile as a conditional set of configurations. I usually set up a dev profile for speed and a prod profile for rigor. In my pom.xml, I'll define these inside a <profiles> block. I'll use a property called db.url that changes based on the active profile.
<profiles>
<profile>
<id>dev</id>
<properties>
<db.url>jdbc:h2:mem:devdb</db.url>
<log.level>DEBUG</log.level>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>prod</id>
<properties>
<db.url>jdbc:postgresql://prod-server:5432/myapp</db.url>
<log.level>ERROR</log.level>
</properties>
</profile>
</profiles>
By setting activeByDefault to true for dev, I don't have to type anything extra when I'm just running tests locally. It just works.
Adding a Quality Gate with the Checkstyle Plugin
Now, I don't want my local build to fail just because I forgot a space before a curly brace—that's annoying when you're prototyping. But for a production build? That's non-negotiable. I'll use the maven-checkstyle-plugin. Instead of putting it in the global <build> section, I'll tuck it inside the prod profile.
<profile>
<id>prod</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.3.1</version>
<executions>
<execution>
<id>validate</id>
<phase>validate</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
<configuration>
<consoleOutput>true</consoleOutput>
<failsOnError>true</failsOnError>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<db.url>jdbc:postgresql://prod-server:5432/myapp</db.url>
</properties>
</profile>
The "Missing Property" Headache
Here is where I messed up. I tried to run mvn clean install -Pprod, and I noticed that while the Checkstyle plugin was running, my application was still picking up the dev database URL in some of my filtered resource files. I realized I had defined a default <db.url> in the main <properties> section of the POM, thinking it would be a safe fallback.
The problem is that Maven property precedence can be tricky. If you define a property in the global section and also in a profile, the profile should win—but I had a typo in the profile property name (I wrote <database.url> instead of <db.url>). Because the profile property didn't match the global one exactly, Maven just kept using the global dev value. I spent twenty minutes scratching my head before I noticed the extra "abase" in the name. Always double-check your property keys when profiles aren't behaving.
Triggering the Custom Build
To put this into action, you use the -P flag. If I want to run my "strict" production build, I'll run:
mvn clean install -Pprod
If I just run mvn clean install, Maven sees the activeByDefault flag on the dev profile. It skips Checkstyle and uses the H2 in-memory database. This separation of concerns keeps the developer experience fast while keeping the production pipeline safe.
📋 Practical Task
Implementing a QA Environment Profile for the Database Migrator
You are working on a project that has dev and prod profiles, but the team has requested a qa profile for the staging server. Your task is to modify the pom.xml to support this.
- Create a new profile with the ID
qa. - Inside the
qaprofile, set a propertydb.urltojdbc:postgresql://qa-server:5432/testdb. - Add the
maven-antrun-pluginto theqaprofile only. Configure it to execute a simple echo command:"Deploying to QA Environment..."during thepackagephase. - Ensure that the
devprofile remains the default.
Verify your work by running mvn package -Pqa and ensuring the Antrun message appears in the console output, while running mvn package (without the flag) does not trigger the message.
There are no comments for now.