2

Background: I want to validate XML-files against a schema automatically. For this I created a maven-project and a XMLValidator-class in src/main/java.

To run the tests I created a XMLValidatorTest in src/test/java. My idea was to put the XML and XSD files, I want to validate, into the src/test/resources folder and "grab" them by their filename. But when I run mvn test the files are not found.

My test-class:

public class XMLValidatorTest {

  XMLValidator xmlvalidator;

  // XSD is in src\test\resources\XSD\myXSD.xsd
  String xsdFileNameWithPath = "XSD\\myXSD.xsd";

  @Before
  public void setup() {
    xmlvalidator = new XMLValidator();
  }

  @Test
  public void testValidate() {

    // XML is in src\test\resources\XML\test001.xml
    String xmlFileNameWithPath = "XML\\test001.xml";


    assertTrue(xmlvalidator.validate(xmlFileNameWithPath, xsdFileNameWithPath));
  } 
}

When I run mvn test I get a file not found exception for e.g. java.io.FileNotFoundException: D:\workspace_eclipse\XSDTester\XSD\myXSD.xsd - which is right as it's in the resource folder.

I tried the solution from Maven (surefire): copy test resources from src/test/java by copying the files via a <testresources>-tag but it has no effect.

<build>
  <testResources>
    <testResource>
      <directory>${project.basedir}/src/test/resources</directory>
    </testResource>
  </testResources>
</build>

Any advise?

P.S. In my XMLValidator I try to use the given files via:

Source xmlFile = new StreamSource(new File(xmlFileNameWithPath));
Source xsdFile = new StreamSource(new File(xsdFileNameWithPath));

edit

I'm again trying to implement Michele Sacchetti advise using a this.getClass().getResourceAsStream().

So to retrieve the XML file I try this

validate (String xmlFileNameWithPath, String xsdFileNameWithPath) {

  Source xmlFile;
  try {
    // give systemid according to: https://stackoverflow.com/questions/10997453/java-xml-validation-does-not-work-when-schema-comes-from-classpath
    xmlFile = new StreamSource(getClass().getResourceAsStream(xmlFileNameWithPath), getClass().getResource(xsdFileNameWithPath).toString());
  } catch (Exception e) {
    System.out.println("XML is null");
    return false;   
  } 

  // ...  further steps, trying to get the XSD and validate them
}

and call the function via (as Michele Sacchetti said with omiting src\test\resources)

// XSD is in src\test\resources\XSD\myXSD.xsd
String xsdFileNameWithPath = "XSD\\myXSD.xsd";

// XML is in src\test\resources\XML\test001.xml
String xmlFileNameWithPath = "XML\\test001.xml";

validate(xmlFileNameWithPath, xsdFileNameWithPath);

But I always get a NPE then trying to get the StreamSource for the file.

Community
  • 1
  • 1
bish
  • 3,381
  • 9
  • 48
  • 69
  • https://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getResourceAsStream%28java.lang.String%29. – Aleksandr M Apr 25 '16 at 11:11
  • What about using [xml-maven-plugin](http://www.mojohaus.org/xml-maven-plugin/validate-mojo.html) to validate those files? – khmarbaise Apr 25 '16 at 11:48
  • @khmarbaise Would be a workaround for positive cases if I don't find an solution. – bish Apr 25 '16 at 12:14
  • @AleksandrM See comment on Michele Sacchetti's answer. I only get a stream on a particular file, but imports/includes are not solved – bish Apr 25 '16 at 12:14
  • @bish Import/includes should be resolved by the lib you're using to validate xml. Maybe you can set custom resolver for it. – Aleksandr M Apr 25 '16 at 12:24
  • This approach can be used as *custom XML validation* during build-/test-phase in Maven, alternative to [XML DTD/Schema validation in Maven](https://stackoverflow.com/q/1527847/5730279) – hc_dev Feb 23 '21 at 23:56

1 Answers1

4

Do not try to access files through filename but use this.getClass().getResourceAsStream() method to access them via CLASSPATH (you must omit starting /src/test/resources)

in the sample bleow file is under

src/test/resources/test/test.properties

pom.xml

<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>
  <groupId>test</groupId>
  <artifactId>test</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <name>test</name>
  <dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.10</version>
        <type>jar</type>
        <scope>test</scope>
    </dependency>
  </dependencies>
</project>

Test source

package test;

import java.io.IOException;
import java.net.URISyntaxException;
import org.junit.Test;

public class ReadFileTest {


    @Test
    public void readTest() throws IOException, URISyntaxException{
        System.out.println(ReadFileTest.class.getResource("test.properties").toURI());
    }

}

mvn clean test output

[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building test 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ test ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 0 resource
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ test ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ test ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 1 resource
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ test ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ test ---
[INFO] Surefire report directory: /Users/msacchetti/fworks/oss_projects/test/target/surefire-reports

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running test.ReadFileTest
file:/Users/msacchetti/fworks/oss_projects/test/target/test-classes/test/test.properties
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.037 sec

Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.318 s
[INFO] Finished at: 2016-04-26T21:36:54+02:00
[INFO] Final Memory: 10M/245M
[INFO] ------------------------------------------------------------------------

note that the returning path is correctly into the target folder and not in src one

  • Well by default you are right, but how to handle imports/includes inside the XSD? – bish Apr 25 '16 at 11:54
  • Not sure I got the whole picture, can you provide some sample of files you are trying to validate? I expect all needed file to be available in the same classpath structure. If a path remapping is needed you should a use a dom parser to manipulate data to be validated. If the code you post above is enough you can use classloader to get the resources in the proper way and then extract the path from it. – Michele Sacchetti Apr 25 '16 at 12:27
  • My XSD is splitted into several files using import/include like `schemaLocation="../../Std/Standardtypen.xsd"`. If I try to load the "highest" XSD (which imports other xsds, which again also import other xsds) using your `this.getClass().getResourceAsStream()` those imports are not solved and my validation failes. – bish Apr 25 '16 at 12:37
  • But I'm expecting you to have the very same problem using filename as well, don't you? – Michele Sacchetti Apr 25 '16 at 12:46
  • No I don't have the problem if I use filename: `Source xmlFile = new StreamSource(new File(xsdFileNameWithPath));` works if I give the full qualified path to the XSD. All imports and includes are solved correctly. – bish Apr 25 '16 at 12:54
  • ok, so as suggested above use the classloader just to retrieve the file in the correct way, then you can get the absolute filename from the resulting object to be passed to your methods. – Michele Sacchetti Apr 25 '16 at 12:58
  • Please look at my edit, I'm always getting a NPE if I try using `getResourcesAsStream` :/ – bish Apr 26 '16 at 05:37
  • Where are your files located? Can you try putting them directly into src/main/test and pass just the filename to the method? Not sure if windows "\\" path sepatator is fine or you can use linux "/" Path relative to resource directory should work as expected. – Michele Sacchetti Apr 26 '16 at 05:59
  • I tried putting them directly into `src\main\test`, `src\main\ressources`, tried using filename with and without path, tried different path seperators (`\\` and `/`), tried basedir specifications ( `"", "/", "./", ".\\", "\\"`) but nothing works. The files are always not found and I'm running out of time... – bish Apr 26 '16 at 06:46
  • Maybe a silly question but are you running test via maven? Such folder must be in classpath for the method to work. – Michele Sacchetti Apr 26 '16 at 07:29
  • As mentioned in my question I use maven with command `mvn clean test`. As per default maven configuration the resources inside `sry/test/resources` should be available on classpath through maven. – bish Apr 26 '16 at 08:25
  • Thank you, I now get access to the files and need to implement an entity resolver - but that's not part of the question here. – bish Apr 27 '16 at 07:20