views:

97

answers:

2

I have a maven mantained project with some modules . One module contains one XML file and one parsing class.

Second module depends on the first module. There is a class that calls the parsing class in the first module , but maven seems cannot test the class in the second module. Maven test reports :

java.lang.NullPointerException
 at java.util.Properties.loadFromXML(Properties.java:851)
 at foo.firstModule.Parser.<init>(Parser.java:92)
 at foo.secondModule.Program.<init>(Program.java:84)

In "Parser.java" (in the first module) , it uses Properties and InputStream to read/parse an XML file :

InputStream xmlStream = getClass().getResourceAsStream("Data.xml");
Properties properties = new Properties();
properties.loadFromXML(xmlStream);

The "data.xml" is located in first module's resources/foo/firstModule directory , and it tests OK in the first module.

It seems when testing the second module , maven cannot correctly load the Data.xml in the first module .

I thought I can solve the problem by using maven-dependency-plugin:unpack to solve it . In the second module's POM file , I add these snippets :

<plugin>
 <groupId>org.apache.maven.plugins</groupId>
 <artifactId>maven-dependency-plugin</artifactId>
 <version>2.1</version>
  <executions>
    <execution>
      <id>data-copying</id>
      <phase>test-compile</phase>
      <goals>
        <goal>unpack</goal>
      </goals>
      <configuration>
        <artifactItems>
          <artifactItem>
            <groupId>foo</groupId>
            <artifactId>firstModule</artifactId>
            <type>jar</type>
            <includes>foo/firstModule/Data.xml</includes>
            <outputDirectory>${project.build.directory}/classes</outputDirectory>
          </artifactItem>
        </artifactItems>
      </configuration>
    </execution>        
  </executions>
</plugin>

In this POM file , I try to unpack the first module , and copy the Data.xml to classes/foo/firstModule/ directory , and then run tests.

And indeed , it is copied to the right directory , I can find the "Data.xml" file in "target/classes/foo/firstModule" directory. But maven test still complains it cannot read the File (Properties.loadFromXML() throws NPE).

I don't know how to solve this problem. I tried other output directory , such as ${project.build.directory}/resources , and ${project.build.directory}/test-classes , but all in vain...

Any advices now ? Thanks in advanced.

Environments : Maven 2.2.1 , eclipse , m2eclipse

---- updated ----

Sorry , I forget to mention , that the Program in the 2nd module , extends the Parser in the 1st module , and in the Parser's constructor , properties are loaded and parsed. In fact , Program is another Parser with further capabilities... ...

I think it may be because Program extends Parser , causing the problem (maybe classloader issues) .

If I disconnect the "inheritance " , initializing (new) the Parser in Program , it will be OK , test passes ! But I cannot change the inheritance relationship ... it's designed ...

Any solutions now ?

---- update with full code ----

This is Parser in the first module :

package foo.firstModule;

import java.io.IOException;
import java.io.InputStream;
import java.util.InvalidPropertiesFormatException;
import java.util.Properties;

public class Parser
{
  private Properties properties;

  public Parser()
  {
    InputStream xmlStream = getClass().getResourceAsStream("Data.xml");
    properties = new Properties();
    try
    {
      properties.loadFromXML(xmlStream);
    }
    catch (InvalidPropertiesFormatException e)
    {
      e.printStackTrace();
    }
    catch (IOException e)
    {
      e.printStackTrace();
    }
  }

  public Properties getProperties()
  {
    return properties;
  }
}

This is Parser's test case , passed .

package foo.firstModule;

import junit.framework.TestCase;

public class ParserTest extends TestCase
{
  public void testParser()
  {
    Parser p = new Parser();
    assertEquals(64 , p.getProperties().size());
  }
}

This is ParserExtend in the secondModule , which extends Parser in the firstModule :

package foo.secondModule;

import java.util.Properties;

import foo.firstModule.Parser;

public class ParserExtend extends Parser
{
  private Properties properties;

  public ParserExtend()
  {
    this.properties = getProperties();
  }

  public int getSize()
  {
    return properties.size();
  }
}

This is ParserExtend's test case :

package foo.secondModule;

import junit.framework.TestCase;

public class ParserExtendTest extends TestCase
{
  public void testParserExtend()
  {
    ParserExtend pe = new ParserExtend();
    assertEquals(64 , pe.getSize());
  }
}

The above test case failed because Properties.loadFromXML(Properties.java:851) throws NPE

However , if I don't extend Parser , just new the Parser :

package foo.secondModule;

import java.util.Properties;

import foo.firstModule.Parser;

public class ParserInit
{
  private Properties properties;

  public ParserInit()
  {
    Parser p = new Parser();
    this.properties = p.getProperties();
  }

  public int getSize()
  {
    return properties.size();
  }
}

and this is the test case :

package foo.secondModule;

import junit.framework.TestCase;

public class ParserInitTest extends TestCase
{
  public void testParserInit()
  {
    ParserInit pi = new ParserInit();
    assertEquals(64 , pi.getSize());
  }
}

The test case passes !

This is my whole test scenario. Anybody able to find how to pass the ParserExtend's test case ? Thanks in advanced.

A: 

It seems when testing the second module , maven cannot correctly load the Data.xml in the first module.

I created the exact same structure and I can't reproduce your problem. My Program class in the second module uses the Parser class from the first module which load properties from an XML file without any problem. Tested under Eclipse and on the command line.

I thought I can solve the problem by using maven-dependency-plugin:unpack to solve it.

Using dependency:unpack is definitely not a solution and if the first JAR contains foo/firstModule/Data.xml, using the Parser class from another module should just work. There must be something wrong somewhere else. If you can upload a representative test project, then please do so and I'll look at ti. Without a project allowing to reproduce, I'm afraid the best answer you'll get is "debug your code" :)

Pascal Thivent
Hi , please try to make Program extends Parser , and in Parser's constructor , do the parsing job , and re-run the tests ... (this is how my architecture works...)If it works for you , i have to check into my code more deeply...
smallufo
@smallufo: Please update your question to show your code so that I can reproduce.
Pascal Thivent
Thank you , I've added further comments in the tail of the question.
smallufo
@smallufo I'm sorry but I'm not going to try to guess how your code works (and I'm not going to ask you a third time to show some code allowing to reproduce).
Pascal Thivent
Thanks for replying . I've appended my full code with test cases... Hope it helps...
smallufo
A: 

I agree, it sounds like classloader issues.

If you always intend on having Data.xml in /foo/firstModule/Data.xml location, give this a try in foo.firstModule.Parser:

InputStream xmlStream = getClass().getResourceAsStream("/foo/firstModule/Data.xml");

Or, if you're explicitly wanting the behavior of finding a "local" Data.xml should firstModule be reused elsewhere (e.g. secondModule or thirdModule has its own Data.xml), try this:

InputStream xmlStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("Data.xml");

scotth
Hi , thanks for replying.If I change to Thread.currentThread().getContextClassLoader().getResourceAsStream("Data.xml");The ParserTest will fail too.
smallufo