mtedone / podam

PODAM - POjo DAta Mocker
https://mtedone.github.io/podam
MIT License
323 stars 750 forks source link

Missing JAX-WS dependency in Java 9 #264

Closed mjustin closed 6 years ago

mjustin commented 6 years ago

Code using PODAM can fail when run under Java 9 due to javax.xml.ws.Holder no longer being on the classpath:

java.lang.NoClassDefFoundError: javax/xml/ws/Holder
    at uk.co.jemos.podam.api.PodamFactoryImpl.fillCollection(PodamFactoryImpl.java:1210)
    at uk.co.jemos.podam.api.PodamFactoryImpl.resolveCollectionValueWhenCollectionIsPojoAttribute(PodamFactoryImpl.java:1081)
    at uk.co.jemos.podam.api.PodamFactoryImpl.manufactureAttributeValue(PodamFactoryImpl.java:943)
    at uk.co.jemos.podam.api.PodamFactoryImpl.populateReadWriteField(PodamFactoryImpl.java:840)
    at uk.co.jemos.podam.api.PodamFactoryImpl.populatePojoInternal(PodamFactoryImpl.java:616)
    at uk.co.jemos.podam.api.PodamFactoryImpl.manufacturePojoInternal(PodamFactoryImpl.java:526)
    at uk.co.jemos.podam.api.PodamFactoryImpl.doManufacturePojo(PodamFactoryImpl.java:429)
    at uk.co.jemos.podam.api.PodamFactoryImpl.manufacturePojo(PodamFactoryImpl.java:151)
    at test.PodamJava9Test.failOnMissingJaxWsDependency(PodamJava9Test.java:23)

Unlike previous versions, Java 9 does not include the JAX-WS on the classpath by default. This means that code written and compiled against Java 8, but run under Java 9 can fail due to these classes not being on the classpath.

A workaround is to add the jaxws-api as a dependency in the POM.

Fix

While this could be fixed by adding jaxws-api as a dependency to pom.xml, I would argue that this is not the right fix. The only class being used is javax.xml.ws.Holder, and none of the actual JAX-WS functionality is being used. It seems like PODAM should just write its own Holder class and use that, e.g.:

public class Holder<T> {
    public T value;

    public Holder() {
    }

    public Holder(T value) {
        this.value = value;
    }
}

It looks like the Holder is only used for TypeManufacturerUtil.findCollectionSize() as a way for that class to change the AttributeStrategy to use in the case of a PodamCollection annotation. Alternatively, this could be refactored to no longer change the strategy to use via a method side effect, but instead have it be part of the return value.

Test Case

pom.xml

<?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>

    <groupId>test</groupId>
    <artifactId>podam-java9</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <java.version>1.8</java.version>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>uk.co.jemos.podam</groupId>
            <artifactId>podam</artifactId>
            <version>7.1.1.RELEASE</version>
            <scope>test</scope>
        </dependency>
        <!-- Enabling this dependency allows this to work in Java 9 -->
        <!--<dependency>-->
            <!--<groupId>javax.xml.ws</groupId>-->
            <!--<artifactId>jaxws-api</artifactId>-->
            <!--<version>2.3.0</version>-->
            <!--<scope>test</scope>-->
        <!--</dependency>-->
    </dependencies>
</project>

PodamJava9Test.java

package test;

import org.junit.Test;
import uk.co.jemos.podam.api.PodamFactoryImpl;

import java.util.List;

public class PodamJava9Test {
    private static class Pojo {
        private List<String> listProperty;

        public List<String> getListProperty() {
            return listProperty;
        }

        public void setListProperty(List<String> listProperty) {
            this.listProperty = listProperty;
        }
    }

    @Test
    public void failOnMissingJaxWsDependency() {
        new PodamFactoryImpl().manufacturePojo(Pojo.class);
    }
}
$ java -version
java version "9.0.4"
Java(TM) SE Runtime Environment (build 9.0.4+11)
Java HotSpot(TM) 64-Bit Server VM (build 9.0.4+11, mixed mode)
$ mvn test

[...]
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.229 sec <<< FAILURE!
failOnMissingJaxWsDependency(test.PodamJava9Test)  Time elapsed: 0.103 sec  <<< ERROR!
java.lang.NoClassDefFoundError: javax/xml/ws/Holder
    at uk.co.jemos.podam.api.PodamFactoryImpl.fillCollection(PodamFactoryImpl.java:1210)
    at uk.co.jemos.podam.api.PodamFactoryImpl.resolveCollectionValueWhenCollectionIsPojoAttribute(PodamFactoryImpl.java:1081)
    at uk.co.jemos.podam.api.PodamFactoryImpl.manufactureAttributeValue(PodamFactoryImpl.java:943)
    at uk.co.jemos.podam.api.PodamFactoryImpl.populateReadWriteField(PodamFactoryImpl.java:840)
    at uk.co.jemos.podam.api.PodamFactoryImpl.populatePojoInternal(PodamFactoryImpl.java:616)
    at uk.co.jemos.podam.api.PodamFactoryImpl.manufacturePojoInternal(PodamFactoryImpl.java:526)
    at uk.co.jemos.podam.api.PodamFactoryImpl.doManufacturePojo(PodamFactoryImpl.java:429)
    at uk.co.jemos.podam.api.PodamFactoryImpl.manufacturePojo(PodamFactoryImpl.java:151)
    at test.PodamJava9Test.failOnMissingJaxWsDependency(PodamJava9Test.java:23)
[...]

Results :

Tests in error: 
  failOnMissingJaxWsDependency(test.PodamJava9Test): javax/xml/ws/Holder

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

This test case passes when run in Java 8.

daivanov commented 6 years ago

Fixed in podam 7.2.0.

anidotnet commented 6 years ago

@daivanov is there any tentative date for the release of 7.2.0? I need this fix for nitrite.

daivanov commented 6 years ago

Hi,

Podam 7.2.0 has been released now. It will appear in Maven central soon.

Thanks, Daniil