maven

Java: Add lib folder to classpath

Adding non standard, non-maven, custom jars in a maven project is a common issue. And this SO post is usually the first googled result. But here is another easier way: Use addjars-maven-plugin. Its easier, no need to run any script, no installing of jars manually, or use the dreaded system scope. Using this also means, the shaded uber jar that gets created will contain the custom jars.

How to use?

Add the jars to a lib folder directly inside the project directory (the project directory now contains lib, src and other usual stuff). Now add this to the pom:

<build>
    <plugins>
        <plugin>
            <groupId>com.googlecode.addjars-maven-plugin</groupId>
            <artifactId>addjars-maven-plugin</artifactId>
            <version>1.0.5</version>
            <executions>
                <execution>
                    <goals>
                        <goal>add-jars</goal>
                    </goals>
                    <configuration>
                        <resources>
                            <resource>
                                <directory>${project.basedir}/lib</directory>
                            </resource>
                        </resources>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

This may not be recognised by the IDE (my Intellij didn’t), but it will work via CLI. So no worries! Very useful in those rare cases, where you have a dozen of custom jars!

Advertisements

Creating a Maven Spring-REST project

Open Eclipse. Make sure it is a recent version with m2e integration. I am using Kepler version of Eclipse.
Now go to File > New > Maven Project.
rest1

Click Next. Select maven-archetype-webapp.
rest2
Click Next. Enter GroupID (group ID is the name that refers to a group of projects. It should be unique. A name like ‘com.companyname.yourname’ would be suffice) and Artifact ID (Artifact ID is the project name. It should be unique within a groupID).

There can be several projects under the same GroupID, but ArtifactID should be different for each project. I have given GroupID as ‘me.sinu.jugaad’ and ArtifactID as ‘rest’.
rest3
Click Finish to create the project.

The webapp archetype would have created the necessary folder structure and a web.xml for you. This web.xml might be for older Servlets without support for Servlet v.3, it doesn’t matter as we’ll overwrite it later.
You might examine pom.xml now, it may contain a single dependency of jUnit(even if you won’t find it its fine 🙂 )

Now lets examine the dependencies we might require for our simple project:

  • We are building REST services, so we need REST api (javax.ws.rs-api) and an implentation for it. We’ll use Apache CXF implementation (cxf-bundle-jaxrs).
  • We’ll use Spring to wire the beans and for dependency injection. So we need a bunch of Spring libraries (spring-web and spring-context should be enough for our skeleton project. spring-context is needed for ContextLoaderListener which loads the beans by scanning some Spring context xml configuration files)
  • We’ll use a JSON provider which helps in converting object to/from JSON. It is not needed for this skeleton project, but its usually handy in almost all REST projects. So we’ll add one such provider (jackson-jaxrs-json-provider) just in case we need it in future.

Here is the pom.xml:

Now create a java folder under src/main. Create a package (me.sinu.jugaad.rest) and a class file inside it(HelloWorld.java).
We’ll just tell a simple “Hello REST!” from our REST service. Here is the class:

Now we’ll create a Spring configuration file under WEB-INF folder, say rest-context.xml:

In this we just defined our helloWorld bean and hooked it up with our JAXRS servlet. We also provided our JSON provider to it to automatically do any marshalling/unmarshalling. You may provide your own providers, which will be necessary as the app grows. Providers can contain Filters or other interceptors.

Now lets define our webapp’s web.xml:

We specify ‘contextConfigLocation‘ for the Spring’s ‘ContextLoaderListener‘ to pick it up as the webapp is loaded. The contextConfigLocation can be given as exact file names or using wild cards.
Since we are using CXF implementation, a CXF servlet is used. The address for our servlet is “/services” and that for our ‘helloREST‘ JAX RS server is “/greet“.
So “WAR_FILE/services/greet” will take us to the JAXRS server. Our simple GET function is annotated with @Path(“/hello”), so to access this we should give as follows: “WAR_FILE/services/greet/hello“.
Now run the project – right-click the project > Run As > Run on server. You might choose a server like Tomcat server v.7. Now in a browser go to “http://localhost:8080/rest/services/greet/hello” (here ‘rest‘ is the WAR file name).

If you see “Hello REST!” everything is fine, else, Dr.Watson, we have a problem 😉

Maven config for SLF4J and Logback

To use SLF4J and logback together, add the following to pom.xml:

<dependency>
 <groupId>org.slf4j</groupId>
 <artifactId>slf4j-api</artifactId>
 <version>1.7.5</version>
 </dependency>
 <dependency>
 <groupId>ch.qos.logback</groupId>
 <artifactId>logback-classic</artifactId>
 <version>1.0.13</version>
 <scope>runtime</scope>
 </dependency>

<dependency>
 <groupId>junit</groupId>
 <artifactId>junit</artifactId>
 <version>3.8.1</version>
 <scope>test</scope>
 </dependency>

Now SLF4J’s logger can be used:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
....
private final Logger logger =  LoggerFactory.getLogger(MyClass.class);
...
logger.debug("Mandatory fields are missing");

If while running this in Eclipse or in console, it complains of some missing configuration, add thisto pom.xml:

<build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.eclipse.m2e</groupId>
                    <artifactId>lifecycle-mapping</artifactId>
                    <version>1.0.0</version>
                    <configuration>
                        <lifecycleMappingMetadata>
                            <pluginExecutions>
                                <pluginExecution>
                                    <pluginExecutionFilter>
                                        <groupId>org.codehaus.mojo</groupId>
                                        <artifactId>properties-maven-plugin</artifactId>
                                        <versionRange>[1.0-alpha-2,)</versionRange>
                                        <goals>
                                            <goal>set-system-properties</goal>
                                        </goals>
                                    </pluginExecutionFilter>
                                    <action>
                                        <ignore />
                                    </action>
                                </pluginExecution>
                            </pluginExecutions>
                        </lifecycleMappingMetadata>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>properties-maven-plugin</artifactId>
                <version>1.0-alpha-2</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>set-system-properties</goal>
                        </goals>
                        <configuration>
                            <properties>
                                <property>
                                    <name>logback.configurationFile</name>
                                    <value>src/main/resources/logback.xml</value>
                                </property>
                            </properties>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

Here “src/main/resources/logback.xml” has the logback configuration. Even if it is not present output may be sent to console