0

I am working with WebSphere Liberty 19.0.0.2 with webProfile-8.0 feature which supports jaxrs-2.1 and beanValidation-2.0. For better support for MutiPart streaming I am using Jersey as JAX-RS implementation instead of liberty's default Apache CXF.

Some more contextual information about versioning of relevant components

Bean Validation 1.1 (JSR 349), Bean Validation 2.0 (JSR 380)

I want to use bean validation 2.0 feature to validate request/response/params in my REST Resource class and for that I need use Jersey's extension for bean validation. https://eclipse-ee4j.github.io/jersey.github.io/documentation/latest/bean-validation.html

As you can see on this link (if you scroll down) the latest version of the extension (2.30.1) also refer to JSR-349 which is bean validation 1.1.

MENIFEST of the jar from following gradle dependency also mention JSR-349

compile group: 'org.glassfish.jersey.ext', name: 'jersey-bean-validation', version: '2.30'

enter image description here

Its surprising that there is no Jersey extension for Bean Validation 2.0 (JSR 380).

When I use above dependency in liberty, bean validation works but I get following error on server startup because of bean validation annotation usage in my resource class.

[3/5/20 18:11:28:597 EST] 00000020 id=00000000 org.glassfish.jersey.model.Parameter                         2 Unable to get the com.sun.proxy.$Proxy70 annotation value property
java.lang.NoSuchMethodException: javax.validation.constraints.NotNull.value()
    at java.lang.Class.getMethod(Class.java:1786)
    at org.glassfish.jersey.model.Parameter.getValue(Parameter.java:453)
    at org.glassfish.jersey.model.Parameter.create(Parameter.java:270)
    at org.glassfish.jersey.model.Parameter.createList(Parameter.java:400)
    at org.glassfish.jersey.model.Parameter.createList(Parameter.java:383)
    at org.glassfish.jersey.server.model.Parameter.create(Parameter.java:137)
    at org.glassfish.jersey.server.model.Invocable.<init>(Invocable.java:215)
    at org.glassfish.jersey.server.model.Invocable.create(Invocable.java:161)
    at org.glassfish.jersey.server.model.ResourceMethod$Builder.createInvocable(ResourceMethod.java:541)
    at org.glassfish.jersey.server.model.ResourceMethod$Builder.build(ResourceMethod.java:522)
    at org.glassfish.jersey.server.model.Resource$Builder.processMethodBuilders(Resource.java:647)
    at org.glassfish.jersey.server.model.Resource$Builder.buildResourceData(Resource.java:583)
    at org.glassfish.jersey.server.model.Resource$Builder.build(Resource.java:639)
    at org.glassfish.jersey.server.model.Resource.from(Resource.java:782)
    at org.glassfish.jersey.server.ResourceBagConfigurator.init(ResourceBagConfigurator.java:55)
    at org.glassfish.jersey.server.ApplicationHandler.initialize(ApplicationHandler.java:331)
    at org.glassfish.jersey.server.ApplicationHandler.lambda$initialize$1(ApplicationHandler.java:293)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:292)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:274)
    at org.glassfish.jersey.internal.Errors.processWithException(Errors.java:232)
    at org.glassfish.jersey.server.ApplicationHandler.initialize(ApplicationHandler.java:292)
    at org.glassfish.jersey.server.ApplicationHandler.<init>(ApplicationHandler.java:259)
    at org.glassfish.jersey.servlet.WebComponent.<init>(WebComponent.java:311)
    at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:154)
    at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:347)
    at javax.servlet.GenericServlet.init(GenericServlet.java:244)
    at com.ibm.ws.webcontainer.servlet.ServletWrapper.init(ServletWrapper.java:291)
    at com.ibm.ws.webcontainer.servlet.ServletWrapper.loadOnStartupCheck(ServletWrapper.java:1373)
    at com.ibm.ws.webcontainer.webapp.WebApp.doLoadOnStartupActions(WebApp.java:1157)
    at com.ibm.ws.webcontainer.webapp.WebApp.commonInitializationFinally(WebApp.java:1125)
    at com.ibm.ws.webcontainer.webapp.WebApp.initialize(WebApp.java:1023)
    at com.ibm.ws.webcontainer.webapp.WebApp.initialize(WebApp.java:6619)
    at com.ibm.ws.webcontainer.osgi.DynamicVirtualHost.startWebApp(DynamicVirtualHost.java:467)
    at com.ibm.ws.webcontainer.osgi.DynamicVirtualHost.startWebApplication(DynamicVirtualHost.java:462)
    at com.ibm.ws.webcontainer.osgi.WebContainer.startWebApplication(WebContainer.java:1152)
    at com.ibm.ws.webcontainer.osgi.WebContainer.access$000(WebContainer.java:111)
    at com.ibm.ws.webcontainer.osgi.WebContainer$3.run(WebContainer.java:957)
    at com.ibm.ws.threading.internal.ExecutorServiceImpl$RunnableWrapper.run(ExecutorServiceImpl.java:239)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

[3/5/20 18:11:28:598 EST] 00000020 id=00000000 org.glassfish.jersey.model.Parameter                         2 Unable to get the com.sun.proxy.$Proxy29 annotation value property
java.lang.NoSuchMethodException: javax.validation.Valid.value()
    at java.lang.Class.getMethod(Class.java:1786)
    at org.glassfish.jersey.model.Parameter.getValue(Parameter.java:453)
    at org.glassfish.jersey.model.Parameter.create(Parameter.java:270)
    at org.glassfish.jersey.model.Parameter.createList(Parameter.java:400)
    at org.glassfish.jersey.model.Parameter.createList(Parameter.java:383)
    at org.glassfish.jersey.server.model.Parameter.create(Parameter.java:137)
    at org.glassfish.jersey.server.model.Invocable.<init>(Invocable.java:215)
    at org.glassfish.jersey.server.model.Invocable.create(Invocable.java:161)
    at org.glassfish.jersey.server.model.ResourceMethod$Builder.createInvocable(ResourceMethod.java:541)
    at org.glassfish.jersey.server.model.ResourceMethod$Builder.build(ResourceMethod.java:522)
    at org.glassfish.jersey.server.model.Resource$Builder.processMethodBuilders(Resource.java:647)

These error are concerning and not feeling confident to use it. Any advice or help is much appreciated.

Update 03/06/2020 Following is feature manager section from server.xml

<featureManager>
    <!--NOTE: Following are standard features and should not be removed-->
    <feature>servlet-4.0</feature>
    <feature>jndi-1.0</feature>
    <feature>requestTiming-1.0</feature>
    <feature>monitor-1.0</feature>
    <feature>localConnector-1.0</feature>
    <feature>restConnector-2.0</feature>
    <feature>ssl-1.0</feature>

    <!-- Do not add enabled webProfile-8.0 because we want to disable default 
    REST implementation (Apache-CXF) provided by Liberty. We want to use Jersey 
    as our REST implementation because it better support multi-part streaming, -->
    <!-- <feature>webProfile-8.0</feature> -->
    <feature>jsp-2.3</feature>
    <feature>cdi-2.0</feature>
    <feature>managedBeans-1.0</feature>
    <feature>jdbc-4.2</feature>
    <feature>beanValidation-2.0</feature>
    <!-- We need javaMail feature for logback email appender to work -->
    <feature>javaMail-1.6</feature>
</featureManager>

Here is my rest application configuration extending jersey's ResourceConfig class

import javax.ws.rs.ApplicationPath;

import org.glassfish.jersey.logging.LoggingFeature;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.ServerProperties;

@ApplicationPath("/rest")
public class RestApplicationConfig extends ResourceConfig {

    public RestApplicationConfig() {
        super();
        configureResourcesAndFeatures();
    }

    private void configureResourcesAndFeatures() {
        packages(RestApplicationConfig.class.getPackage().getName());
        register(MultiPartFeature.class);

        property(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true);
    }
}

I mentioned use of jersey-bean-validation version 2.30 but I learned that Jersey 2.27 is latest version which is JAVA EE implementation of JAX-RS 2.1 API. Starting 2.28 its Jakarta EE implementation of JAX-RS 2.1. So I would really want to use version 2.27 and make bean validation 2.0 working with it because liberty version I am using has not up to jakarta ee yet.

Rakesh Prajapati
  • 1,078
  • 8
  • 17
  • Can you post your server.xml? Particularly, the features that you are using and the application setting? And the contents of your application? If you are using Jersey instead of the built-in CXF, then you would like likely either be disabling the jaxrs-2.1 feature or you are using parent-last classloading delegation. The latter might be part of the problem here. As for the manifest header, that is most likely an error in the packaging code. I can see from the pom.xml dependencies in the Jersey bean-validation project that it depends on Jakarta Bean Validation 2.0. HTH – Andy McCright Mar 06 '20 at 14:33
  • @AndyMcCright thanks for responding. Updated question with more information you are asked for. As I mentioned in the update liberty version I am using is not up to jakarta ee yet, so I want to really use jersey core and extension version 2.27 to make bean validation 2.0 working. Can you please share url of pom file where you see bean validation api version? – Rakesh Prajapati Mar 06 '20 at 15:01
  • This was the pom.xml I was looking at (master - probably closer to 2.30.1): https://github.com/eclipse-ee4j/jersey/blob/24a0f65b3b4b7a79ff2553c85baf7427ef554cf9/pom.xml#L2119 It should be possible to use the Jakarta EE 8 APIs interchangeably with Java EE 8, so you should be able to use the later Jersey versions (EE 9 is incompatible due to the package name changes) - though that may still not help with this problem. – Andy McCright Mar 06 '20 at 15:05

1 Answers1

1

Cause of all the issues was incorrect META-INF information packaged within jersey-bean-validation jar and also incorrect gradle dependency.

If go to https://mvnrepository.com/artifact/org.glassfish.jersey.ext/jersey-bean-validation/2.27 url and scroll down if you see it includes validation-api 1.1.0.Final and hibernate-validator 5.1.3.Final which for Bean Validation 1.1 (JSR 349). enter image description here

You have to exclude above incorrect transitive dependencies and include correct version for Bean Validation 2.0 (JSR 380) which is Hibernate Validator 6.0 (6.0.18.Final)

If your container already provides implementation of bean validation, you don't need to include hibernate validator jar. In my case enabling beanValidation beanValidation-2.0 in liberty it provides bean validation implementation.

// Jersey 2.27 is latest version which is JAVA EE implementation of JAX-RS 2.1 API. Starting 2.28 its Jakarta EE implementation of JAX-RS 2.1
compile group: 'org.glassfish.jersey.containers', name: 'jersey-container-servlet', version: '2.27'
compile group: 'org.glassfish.jersey.media', name: 'jersey-media-json-jackson', version: '2.27'
compile group: 'org.glassfish.jersey.media', name: 'jersey-media-multipart', version: '2.27'
compile (group: 'org.glassfish.jersey.inject', name: 'jersey-hk2', version: '2.27') {
    exclude group: 'javax.inject', module: 'javax.inject'
}
compile (group: 'org.glassfish.jersey.ext', name: 'jersey-bean-validation', version: '2.27') {
    exclude group: 'javax.el', module: 'javax.el-api'
    exclude group: 'org.hibernate'
}

configurations.compile {
    exclude group: 'javax.validation', module: 'validation-api'
    exclude group: 'javax.annotation', module: 'javax.annotation-api'
}

excluded 2 jars at compile configuration level because they were coming as transitive dependencies from multiple places.

This fixed all issues and bean validation works like charm.

Rakesh Prajapati
  • 1,078
  • 8
  • 17