Java Ninja Chronicles By Norris Shelton

Things I learned in the pursuit of code

This is something that I rarely do because I use IntelliJ IDEA. Here is one of the most complex commands I issue for Maven.

mvn -P dev -DskipTests=true clean install
  • -p dev -> which profile to run
  • -DskipTests=true -> do not run the automated tests
  • clean install -> clean all target directories and run an install

February 13th, 2015

Posted In: Maven

Tags: , , , ,

One Comment

Every once in a while, you have a library that isn’t in a repository and shouldn’t be there for some reason. We had such a library. How do you use that library when it is on your local system instead of in a repository? Use the system scope.

<dependency>
      <groupId>com.this.and.that</groupId>
      <artifactId>non-repo-library</artifactId>
      <version>1.0</version>
      <scope>system</scope>
      <systemPath>/my/path/to/lib.jar</systemPath>
    </dependency>

System scope tells Maven that the dependency is on the file system. System Path tells Maven where to find the dependency.

December 10th, 2014

Posted In: Maven

Tags: , , , ,

Leave a Comment

We were given a project that built a custom server. They had the need to deploy the code and the dependencies. The dependencies were placed in /lib via the maven-dependency-plugin. They were generating the MANIFEST.MF via the maven-jar-plugin. The problem was that what was in the manifest wasn’t exactly what was in the lib directory. An example is in the lib directory, there was a file named adapter-models-1.0-SNAPSHOT.jar. Unfortunately, the manifest contained adapter-models-1.0-20141201.182800-510.jar in the Class-Path, which was the unique snapshot identifier.

I fixed this by adding useUniqueVersions to their manifest element of the maven-jar-plugin.

            <plugin>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <classpathPrefix>lib/</classpathPrefix>
                            <mainClass>com.this.and.that</mainClass>
                            <useUniqueVersions>false</useUniqueVersions>
                        </manifest>
                        <manifestEntries>
                            <Implementation-Version>${project.version}-${changeSet:} (${changeSetDate:})
                            </Implementation-Version>
                        </manifestEntries>
                    </archive>
                </configuration>
            </plugin>

December 1st, 2014

Posted In: Maven

Tags: , , , ,

Leave a Comment

The benefit of having a local Maven repository is that only one developer suffers the delay of the network traffic requests to repo1. If you have a local maven repository and your developers have mirrors setup in their settings.xml

<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
    <mirrors>
        <mirror>
            <id>artifactory</id>
            <mirrorOf>*</mirrorOf>
            <url>http://artifactory.cdinteractive.com:8080/artifactory/repo</url>
            <name>Artifactory</name>
        </mirror>
    </mirrors>
</settings>

March 3rd, 2014

Posted In: Maven

Tags: , , , , ,

One Comment

Springframework MVC 3.2 introduced the ability to test controllers via MockMVC. In this example, we will test a controller that returns JSON via @ResponseBody.

Here are the dependencies that you will need.

            <!-- This is usually included as part of your normal dependencies.  If not, include this way -->
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
                <version>3.1.0</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>${spring.version}</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.mockito</groupId>
                <artifactId>mockito-core</artifactId>
                <version>1.9.5</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>com.jayway.jsonpath</groupId>
                <artifactId>json-path</artifactId>
                <version>${jsonpath.version}</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>com.jayway.jsonpath</groupId>
                <artifactId>json-path-assert</artifactId>
                <version>${jsonpath.version}</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.11</version>
                <scope>test</scope>
            </dependency>

This is an example of the spring context.

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans    http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/mvc      http://www.springframework.org/schema/mvc/spring-mvc.xsd
                           http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context.xsd">

    <mvc:annotation-driven/>

    <context:component-scan base-package="com.cdi.igs.core.spring.web"/>

</beans>

The basic test class needs to have the following annotations, properties and setup defined. Please note the static imports. You want to use these from the mock mvc request builders.

import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

import static org.hamcrest.Matchers.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;


@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration
public class TestGlobalControllerExceptionHandler {

    @Autowired
    private WebApplicationContext wac;

    private MockMvc mockMvc;

    @Before
    public void setup() {
        mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
    }
//...
}

This is an example test method that calls a spring controller that returns a string. We are creating an empty model object that we convert to JSON. We tell the method that we are calling that we are sending JSON, because the method that we are calling expects to be sent a JSON object. We get validation errors in this case, that we compare with our expected results. The JSON response that we get back from the call to the controller is “{“fieldErrors”:[{“message”:”may not be null”},{“message”:”may not be null”}]}

    @Test
    public void testMyMethod() throws Exception {
        mockMvc.perform(post("/mymethod")
                        .content(new ObjectMapper().writeValueAsString(new TargetExceptionModel()))
                        .contentType(MediaType.APPLICATION_JSON))
               .andExpect(status().isBadRequest())
        .andExpect(jsonPath("$.fieldErrors", hasSize(2)))
        .andExpect(jsonPath("$.fieldErrors[*].message", contains("may not be null", "may not be null")))
        .andDo(print());
    }

Here is an example of a controller test method that users other types of matchers. Example data is:

{"status":"SUCCESS","message":null,"previousPage":null,"nextPage":"login/privacy_policy","errors":null,"exception":null,"idSetting":"pri","setting":"privacy-Starfish","value":"test","settingText":"lots and lots of text","date":"01-27-2014"}
    @Test
    public void testGetPrivacyByClientSuccess() throws Exception {
        mockMvc.perform(get("/privacy/pri"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.idSetting", containsString("pri")))
                .andExpect(jsonPath("$.setting", containsString("privacy-Starfish")))
                .andExpect(jsonPath("$.settingText", notNullValue()))
                .andExpect(jsonPath("$.value", containsString("test")))
                .andExpect(jsonPath("$.exception", nullValue()))
                .andDo(print());
    }

I needed to write a method that passed an object that contained an exception object back to the calling method. The data being sent back was:

{"status":"ERROR","message":null,"previousPage":null,"nextPage":null,"errors":null,"exception":{"cause":null,"stackTrace":[{"methodName":"copyProperties","fileName":"PropertyUtilsBean.java","lineNumber":276,"className":"org.apache.commons.beanutils.PropertyUtilsBean","nativeMethod":false},{"methodName":"copyProperties","fileName":"PropertyUtils.java","lineNumber":219,"className":"org.apache.commons.beanutils.PropertyUtils","nativeMethod":false},{"methodName":"getPrivacy","fileName":"LoginService.java","lineNumber":193,"className":"com.cdi.igs.core.login.LoginService","nativeMethod":false},{"methodName":"getPrivacyByClient","fileName":"LoginController.java","lineNumber":94,"className":"com.cdi.igs.services.LoginController","nativeMethod":false},{"methodName":"invoke0","fileName":"NativeMethodAccessorImpl.java","lineNumber":-2,"className":"sun.reflect.NativeMethodAccessorImpl","nativeMethod":true},{"methodName":"invoke","fileName":"NativeMethodAccessorImpl.java","lineNumber":57,"className":"sun.reflect.NativeMethodAccessorImpl","nativeMethod":false},{"methodName":"invoke","fileName":"DelegatingMethodAccessorImpl.java","lineNumber":43,"className":"sun.reflect.DelegatingMethodAccessorImpl","nativeMethod":false},{"methodName":"invoke","fileName":"Method.java","lineNumber":606,"className":"java.lang.reflect.Method","nativeMethod":false},{"methodName":"invoke","fileName":"InvocableHandlerMethod.java","lineNumber":214,"className":"org.springframework.web.method.support.InvocableHandlerMethod","nativeMethod":false},{"methodName":"invokeForRequest","fileName":"InvocableHandlerMethod.java","lineNumber":132,"className":"org.springframework.web.method.support.InvocableHandlerMethod","nativeMethod":false},{"methodName":"invokeAndHandle","fileName":"ServletInvocableHandlerMethod.java","lineNumber":104,"className":"org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod","nativeMethod":false},{"methodName":"invokeHandleMethod","fileName":"RequestMappingHandlerAdapter.java","lineNumber":749,"className":"org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter","nativeMethod":false},{"methodName":"handleInternal","fileName":"RequestMappingHandlerAdapter.java","lineNumber":690,"className":"org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter","nativeMethod":false},{"methodName":"handle","fileName":"AbstractHandlerMethodAdapter.java","lineNumber":83,"className":"org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter","nativeMethod":false},{"methodName":"doDispatch","fileName":"DispatcherServlet.java","lineNumber":945,"className":"org.springframework.web.servlet.DispatcherServlet","nativeMethod":false},{"methodName":"doService","fileName":"DispatcherServlet.java","lineNumber":876,"className":"org.springframework.web.servlet.DispatcherServlet","nativeMethod":false},{"methodName":"processRequest","fileName":"FrameworkServlet.java","lineNumber":961,"className":"org.springframework.web.servlet.FrameworkServlet","nativeMethod":false},{"methodName":"doGet","fileName":"FrameworkServlet.java","lineNumber":852,"className":"org.springframework.web.servlet.FrameworkServlet","nativeMethod":false},{"methodName":"service","fileName":"HttpServlet.java","lineNumber":687,"className":"javax.servlet.http.HttpServlet","nativeMethod":false},{"methodName":"service","fileName":"FrameworkServlet.java","lineNumber":837,"className":"org.springframework.web.servlet.FrameworkServlet","nativeMethod":false},{"methodName":"service","fileName":"TestDispatcherServlet.java","lineNumber":64,"className":"org.springframework.test.web.servlet.TestDispatcherServlet","nativeMethod":false},{"methodName":"service","fileName":"HttpServlet.java","lineNumber":790,"className":"javax.servlet.http.HttpServlet","nativeMethod":false},{"methodName":"doFilter","fileName":"MockFilterChain.java","lineNumber":170,"className":"org.springframework.mock.web.MockFilterChain$ServletFilterProxy","nativeMethod":false},{"methodName":"doFilter","fileName":"MockFilterChain.java","lineNumber":137,"className":"org.springframework.mock.web.MockFilterChain","nativeMethod":false},{"methodName":"perform","fileName":"MockMvc.java","lineNumber":141,"className":"org.springframework.test.web.servlet.MockMvc","nativeMethod":false},{"methodName":"testGetPrivacyByClientFail","fileName":"TestLoginController.java","lineNumber":96,"className":"com.cdi.igs.services.TestLoginController","nativeMethod":false},{"methodName":"invoke0","fileName":"NativeMethodAccessorImpl.java","lineNumber":-2,"className":"sun.reflect.NativeMethodAccessorImpl","nativeMethod":true},{"methodName":"invoke","fileName":"NativeMethodAccessorImpl.java","lineNumber":57,"className":"sun.reflect.NativeMethodAccessorImpl","nativeMethod":false},{"methodName":"invoke","fileName":"DelegatingMethodAccessorImpl.java","lineNumber":43,"className":"sun.reflect.DelegatingMethodAccessorImpl","nativeMethod":false},{"methodName":"invoke","fileName":"Method.java","lineNumber":606,"className":"java.lang.reflect.Method","nativeMethod":false},{"methodName":"runReflectiveCall","fileName":"FrameworkMethod.java","lineNumber":47,"className":"org.junit.runners.model.FrameworkMethod$1","nativeMethod":false},{"methodName":"run","fileName":"ReflectiveCallable.java","lineNumber":12,"className":"org.junit.internal.runners.model.ReflectiveCallable","nativeMethod":false},{"methodName":"invokeExplosively","fileName":"FrameworkMethod.java","lineNumber":44,"className":"org.junit.runners.model.FrameworkMethod","nativeMethod":false},{"methodName":"evaluate","fileName":"InvokeMethod.java","lineNumber":17,"className":"org.junit.internal.runners.statements.InvokeMethod","nativeMethod":false},{"methodName":"evaluate","fileName":"RunBefores.java","lineNumber":26,"className":"org.junit.internal.runners.statements.RunBefores","nativeMethod":false},{"methodName":"evaluate","fileName":"RunBeforeTestMethodCallbacks.java","lineNumber":74,"className":"org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks","nativeMethod":false},{"methodName":"evaluate","fileName":"RunAfterTestMethodCallbacks.java","lineNumber":83,"className":"org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks","nativeMethod":false},{"methodName":"evaluate","fileName":"SpringRepeat.java","lineNumber":72,"className":"org.springframework.test.context.junit4.statements.SpringRepeat","nativeMethod":false},{"methodName":"runChild","fileName":"SpringJUnit4ClassRunner.java","lineNumber":232,"className":"org.springframework.test.context.junit4.SpringJUnit4ClassRunner","nativeMethod":false},{"methodName":"runChild","fileName":"SpringJUnit4ClassRunner.java","lineNumber":89,"className":"org.springframework.test.context.junit4.SpringJUnit4ClassRunner","nativeMethod":false},{"methodName":"run","fileName":"ParentRunner.java","lineNumber":238,"className":"org.junit.runners.ParentRunner$3","nativeMethod":false},{"methodName":"schedule","fileName":"ParentRunner.java","lineNumber":63,"className":"org.junit.runners.ParentRunner$1","nativeMethod":false},{"methodName":"runChildren","fileName":"ParentRunner.java","lineNumber":236,"className":"org.junit.runners.ParentRunner","nativeMethod":false},{"methodName":"access$000","fileName":"ParentRunner.java","lineNumber":53,"className":"org.junit.runners.ParentRunner","nativeMethod":false},{"methodName":"evaluate","fileName":"ParentRunner.java","lineNumber":229,"className":"org.junit.runners.ParentRunner$2","nativeMethod":false},{"methodName":"evaluate","fileName":"RunBeforeTestClassCallbacks.java","lineNumber":61,"className":"org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks","nativeMethod":false},{"methodName":"evaluate","fileName":"RunAfterTestClassCallbacks.java","lineNumber":71,"className":"org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks","nativeMethod":false},{"methodName":"run","fileName":"ParentRunner.java","lineNumber":309,"className":"org.junit.runners.ParentRunner","nativeMethod":false},{"methodName":"run","fileName":"SpringJUnit4ClassRunner.java","lineNumber":175,"className":"org.springframework.test.context.junit4.SpringJUnit4ClassRunner","nativeMethod":false},{"methodName":"run","fileName":"JUnitCore.java","lineNumber":160,"className":"org.junit.runner.JUnitCore","nativeMethod":false},{"methodName":"startRunnerWithArgs","fileName":"JUnit4IdeaTestRunner.java","lineNumber":74,"className":"com.intellij.junit4.JUnit4IdeaTestRunner","nativeMethod":false},{"methodName":"prepareStreamsAndStart","fileName":"JUnitStarter.java","lineNumber":211,"className":"com.intellij.rt.execution.junit.JUnitStarter","nativeMethod":false},{"methodName":"main","fileName":"JUnitStarter.java","lineNumber":67,"className":"com.intellij.rt.execution.junit.JUnitStarter","nativeMethod":false},{"methodName":"invoke0","fileName":"NativeMethodAccessorImpl.java","lineNumber":-2,"className":"sun.reflect.NativeMethodAccessorImpl","nativeMethod":true},{"methodName":"invoke","fileName":"NativeMethodAccessorImpl.java","lineNumber":57,"className":"sun.reflect.NativeMethodAccessorImpl","nativeMethod":false},{"methodName":"invoke","fileName":"DelegatingMethodAccessorImpl.java","lineNumber":43,"className":"sun.reflect.DelegatingMethodAccessorImpl","nativeMethod":false},{"methodName":"invoke","fileName":"Method.java","lineNumber":606,"className":"java.lang.reflect.Method","nativeMethod":false},{"methodName":"main","fileName":"AppMain.java","lineNumber":120,"className":"com.intellij.rt.execution.application.AppMain","nativeMethod":false}],"message":"No origin bean specified","localizedMessage":"No origin bean specified","suppressed":[]},"idSetting":"Starfish1","setting":null,"value":null,"settingText":null,"date":null}
    @Test
    public void testGetPrivacyByClientFail() throws Exception {
        mockMvc.perform(get("/privacy/Starfish1"))
               .andExpect(status().isOk())
               .andExpect(jsonPath("$.idSetting", containsString("Starfish1")))
               .andExpect(jsonPath("$.setting", nullValue()))
               .andExpect(jsonPath("$.settingText", nullValue()))
               .andExpect(jsonPath("$.value", nullValue()))
               .andExpect(jsonPath("$.exception.cause", nullValue()))
               .andExpect(jsonPath("$.exception.stackTrace", notNullValue()))
               .andExpect(jsonPath("$.exception.stackTrace[0].methodName", notNullValue()))
               .andDo(print());
    }

To get the content and store it in a variable outside the test, add .andReturn() to the end of the perform and store the result in a MvcResult, then get the content.

        MvcResult result = mockMvc.perform(post("/login")
                                               .content(
                                                   "{"userName":"screen011","password":"Jason3080!"," +
                                                   ""remoteAddress":"0.0" +
                                                   ".0.0"}"
                                                       )
                                               .contentType(MediaType.APPLICATION_JSON))
               .andExpect(status().isOk())
               .andExpect(jsonPath("$.exception", nullValue()))
               .andExpect(jsonPath("$.errors", hasSize(0)))
               .andExpect((jsonPath("$.ssoToken", notNullValue())))
               .andDo(print())
               .andReturn();
        String content = result.getResponse().getContentAsString();

Then if you need to extract a value out of the JSON, you can use JsonPath out of jayway like

        String content = result.getResponse().getContentAsString();

        assertNotNull(content);
        String ssoToken = JsonPath.read(content, "$.ssoToken");
        assertNotNull(ssoToken);

February 27th, 2014

Posted In: Java, MockMVC, Spring, Spring MVC

Tags: , , , , , , ,

2 Comments

mvn versions:display-dependency-updates

The output is useful, but you still need to interpret it. In this case, there is a beta library that is suggested. Not.

INFO] ------------------------------------------------------------------------
[INFO] Building igs 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- versions-maven-plugin:2.1:display-dependency-updates (default-cli) @ igs ---
[INFO] The following dependencies in Dependency Management have newer versions:
[INFO]   commons-collections:commons-collections ............ 3.2.1 -> 20040616
[INFO]   org.hibernate:hibernate-validator ......... 5.0.1.Final -> 5.1.0.Beta1
[INFO]
[INFO]

In this case, a library with a version number that doesn’t follow the normal version patters is mistakenly noted as a newer version.

[INFO] ------------------------------------------------------------------------
[INFO] Building assets 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- versions-maven-plugin:2.1:display-dependency-updates (default-cli) @ assets ---
[INFO] The following dependencies in Dependency Management have newer versions:
[INFO]   commons-collections:commons-collections ............ 3.2.1 -> 20040616
[INFO]   org.hibernate:hibernate-validator ......... 5.0.1.Final -> 5.1.0.Beta1
[INFO]
[INFO]

February 7th, 2014

Posted In: Maven

Tags: , , , ,

Leave a Comment

I never really understood the use of the bundleFileName in the maven-ear-plugin. Who looks inside the .ear anyway. Well, there is a reason it is there.

I had to set the finalName property in the build section of several Maven modules across several projects. I learned the hard way that Maven modules do not talk to each other. The maven-ear-plugin assumes that the name of the artifacts is the default name. If you use finalName to change the name of the artifact, it is not aware. It configures your ear, but the file that it points to for the ejb or war module will not be there. Doh!

Example of finalName usage in an ejb module:

    <build>
        <finalName>isgwebsupport</finalName>
        <plugins>
            <plugin>
                <artifactId>maven-ejb-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <ejbVersion>3.0</ejbVersion>
                    <generateClient>true</generateClient>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <classpathPrefix>lib/</classpathPrefix>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>

Example of finalName usage in a war module:

    <build>
        <finalName>isgwebsupport</finalName>
        <plugins>
            <plugin>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <!--
                        Needed for skinny war
                        http://maven.apache.org/plugins/maven-war-plugin/examples/skinny-wars.html
                    -->
                    <packagingExcludes>WEB-INF/lib/*.jar</packagingExcludes>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <classpathPrefix>lib/</classpathPrefix>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>

So, if you set the finalName of an ejb module or a web module, you must also set the bundleFileName in the ear module.

NOTE: You must specify the file extension when you use bundleFileName.

Example of the usage of bundleFileName in an ear module:

    <build>
        <finalName>isgwebsupport</finalName>
        <plugins>
            <plugin>
                <artifactId>maven-ear-plugin</artifactId>
                <version>2.7</version>
                <configuration>
                    <version>5</version>
                    <description>ISGWebSupport</description>
                    <displayName>ISGWebSupport</displayName>
                    <defaultLibBundleDir>/lib</defaultLibBundleDir>
                    <skinnyWars>true</skinnyWars>
                    <modules>
                         <webModule>
							<groupId>${project.groupId}</groupId>
                            <artifactId>websupport-war</artifactId>
                            <contextRoot>/giswebsupport</contextRoot>
							<bundleFileName>isgwebsupport.war</bundleFileName>
                        </webModule>
                        <ejbModule>
                            <groupId>${project.groupId}</groupId>
                            <artifactId>websupport-ejb</artifactId>
                            <bundleFileName>isgwebsupport.jar</bundleFileName>
                        </ejbModule>
                    </modules>
                </configuration>
            </plugin>
        </plugins>
    </build>

Lesson learned.

January 18th, 2013

Posted In: Maven

Tags: , , , , , , , , , ,

6 Comments

You would think that this would be terribly easy, but it isn’t. It took several attempts before I figured out what they wanted. Too bad their contextual help doesn’t give you the details.

Select the “Deploy” tab from the top, then select the “Artifacts Bundle” tab from the left. Choose the file you want, then hit deploy.

The tricky part is that they expect very specific things from the file. In my case, I was trying to import the artifact corresponding to

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjtools</artifactId>
    <version>1.6.11</version>
</dependency>

What they don’t tell you is that the name of the file will be part of the groupId. So I ended up with an archive named org.zip. The contents of the archive were:
/aspectj
     /aspectjtools
          /1.6.11
               aspectjtools-1.6.11.jar
               aspectjtools-1.6.11.jar.sha1
               aspectjtools-1.6.11.pom
               aspectjtools-1.6.11.pom.sha1

In hindsight, I might have been able to name the archive org.aspectj.aspectjtools, then inside I could have multiple version directories, each containing their respective artifacts.

January 17th, 2013

Posted In: Maven

Tags: , , , ,

Leave a Comment

Maven EJB MODULES

EJB modules are just like normal, but they also have an manifest section:

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-ejb-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <ejbVersion>3.0</ejbVersion>
                    <generateClient>true</generateClient>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <classpathPrefix>lib/</classpathPrefix>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>
  • manifest – this section is responsible for generating the manifest file and adding the classpath entries

MAVEN WEB MODULES

Do everything like you normally would, except you will need a build section like the following:

    <build>
        <plugins>
            <plugin>
                <!--
                    Needed for skinny war
                    http://maven.apache.org/plugins/maven-war-plugin/examples/skinny-wars.html
                -->
                <artifactId>maven-war-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <packagingExcludes>WEB-INF/lib/*.jar</packagingExcludes>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <classpathPrefix>lib/</classpathPrefix>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>
  • packagingExcludes – tells the plugin to exclude the jar files from the lib directory
  • manifest – this section is responsible for generating the manifest file and adding the classpath entries

MAVEN EAR MODULE

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.appriss.justicexchange.licensemgr</groupId>
        <artifactId>licensemgr-parent</artifactId>
        <version>3.0-SNAPSHOT</version>
    </parent>

    <artifactId>licensemgr-ear</artifactId>
    <packaging>ear</packaging>

    <dependencies>
        <dependency>
            <groupId>${project.groupId}</groupId>
            <artifactId>licensemgr-ejb</artifactId>
            <version>${project.version}</version>
            <type>ejb</type>
        </dependency>
        <dependency>
            <groupId>${project.groupId}</groupId>
            <artifactId>licensemgr-war</artifactId>
            <version>${project.version}</version>
            <type>war</type>
        </dependency>
        <!--
            Also include the war as a type=pom so that it pulls in the dependencies for inclusion in the ear /lib.
        -->
        <dependency>
            <groupId>${project.groupId}</groupId>
            <artifactId>licensemgr-war</artifactId>
            <version>${project.version}</version>
            <type>pom</type>
        </dependency>
    </dependencies>

    <build>
        <finalName>licensemgr-${project.version}</finalName>
        <plugins>
            <plugin>
                <artifactId>maven-ear-plugin</artifactId>
                <version>2.7</version>
                <configuration>
                    <version>5</version>
                    <displayName>ISG License Manager Application</displayName>
                    <description>LicenseManager</description>
                    <defaultLibBundleDir>/lib</defaultLibBundleDir>
                    <skinnyWars>true</skinnyWars>
                    <modules>
                        <ejbModule>
                            <groupId>${project.groupId}</groupId>
                            <artifactId>licensemgr-ejb</artifactId>
                        </ejbModule>
                        <webModule>
                            <groupId>${project.groupId}</groupId>
                            <artifactId>licensemgr-war</artifactId>
                            <contextRoot>licensemgr</contextRoot>
                            <bundleFileName>licensemgr-${project.version}.war</bundleFileName>
                        </webModule>
                    </modules>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

There should normally be a dependency entry for each module that will be packaged into the war. The EJB modules will be included with a of ejb and the WAR modules will be included with a of war. You ALSO need to add an extra dependency for each WAR module with a of pom. This will cause all of the dependencies to be pulled into the ear module and placed in the library bundle directory (/lib). If you don’t do this, you will need to duplicate each dependency of each war module as a dependency of the ear module.

The build section has 2 entries related to skinny wars:

  • defaultLibBundleDir – tells Maven where to bundle the jars
  • skinnyWars – tells Maven that you intend to make skinny wars

January 4th, 2013

Posted In: Java, Maven

Tags: , , , , , ,

2 Comments

Maven is geared around the concept of producing one artifact per Maven module. If you need to have a Maven module produce multiple artifacts, you can use the Maven Assembly plugin to accomplish your goals. If you need the maven assembly plugin to produce two artifacts, it must be with two separate execution blocks. One execution block creates one artifact, like one module typically produces one artifact.

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.3</version>
                <executions>
                    <execution>
                        <id>client</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                        <configuration>
                            <finalName>${project.artifactId}-${project.version}</finalName>
                            <appendAssemblyId>true</appendAssemblyId>
                            <descriptors>
                                <descriptor>src/main/assembly/client.xml</descriptor>
                            </descriptors>
                        </configuration>
                    </execution>
                    <execution>
                        <!-- NOTE This is for backwards compatibility with the original builds-->
                        <id>client-no-version</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                        <configuration>
                            <finalName>licensemgr-3.0-client</finalName>
                            <appendAssemblyId>false</appendAssemblyId>
                            <descriptors>
                                <descriptor>src/main/assembly/client.xml</descriptor>
                            </descriptors>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

June 12th, 2012

Posted In: Maven

Tags: ,

Leave a Comment

LinkedIn Auto Publish Powered By : XYZScripts.com