0

I have been trying to switch from Payara server to Open Liberty, however I am faced with a problem: my code works well on Payara but does not work well on Open Liberty. Here is the simplest code test to illustrate the problem:

ApiEntryPoint.java

@ApplicationPath("/v1")
public class ApiEntryPoint extends Application {

    @Override
    public Map<String, Object> getProperties() {

        Map<String, Object> props = new HashMap<String, Object>();
        props.put("name", "This is my name");
        return props;
    }
}

Test.java

@ApplicationScoped
public class Test {

    @Context
    private Configuration configuration;

    private String name;

    @PostConstruct
    private void init() {
        name = (String) configuration.getProperties().get("name");
    }

    public String getName() {
        return name;
    }
}

TestResources.java

@Path("/test")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@RequestScoped
public class TestResources {

    @Inject
    private Test test;

    @GET
    public String test(@Context HttpHeaders headers, @PathParam("id") int id) {
        return test.getName();
    }
}

As you may guess, this code works on Payara server and when I try to run it on Open Liberty server, I get the following error:

[err] org.jboss.weld.exceptions.WeldException: WELD-000049: Unable to invoke private void      com.domain.test.Test.init() on com.domain.test.Test@74caba3d
[err]   at org.jboss.weld.injection.producer.DefaultLifecycleCallbackInvoker.invokeMethods(DefaultLifecycleCallbackInvoker.java:85)
[err]   at [internal classes]
[err]   at com.domain.test.Test$Proxy$_$$_WeldClientProxy.getName(Unknown Source)
[err]   at com.domain.test.TestResources.test(TestResources.java:25)
[err]   at com.domain.test.TestResources$Proxy$_$$_WeldClientProxy.test(Unknown Source)
[err]   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[err]   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[err]   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[err]   at java.lang.reflect.Method.invoke(Method.java:498)
[err]   at com.ibm.ws.jaxrs20.server.LibertyJaxRsServerFactoryBean.performInvocation(LibertyJaxRsServerFactoryBean.java:656)
[err]   at [internal classes]
[err]   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
[err]   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
[err]   at java.lang.Thread.run(Thread.java:748)
[err] Caused by: java.lang.reflect.InvocationTargetException
[err]   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[err]   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[err]   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[err]   at java.lang.reflect.Method.invoke(Method.java:498)
[err]   at org.jboss.weld.injection.producer.DefaultLifecycleCallbackInvoker.invokeMethods(DefaultLifecycleCallbackInvoker.java:83)
[err]   ... 64 more
[err] Caused by: java.lang.NullPointerException
[err]   at com.domain.test.Test.init(Test.java:18)
[err]   ... 69 more

The last exception tells me the that configuration.getProperties() returns null in Test.java post constructor. Why is this behaving as such in Open Liberty and not in Payara? Also if I don't call test.getName() in TestResources.java text method and just return a random string, I am not getting any error. This begs the question when is @PostConstructor method called? I thought it gets called when the bean is fully initialized and this should happen before the test method executes in TestResources.java. Is there something that I am missing here?

Note that the only dependency I am using in maven is the full jakartaee-8 with a scope of provided.

server.xml

<server description="new server">

    <featureManager>
        <feature>jakartaee-8.0</feature>
        <feature>localConnector-1.0</feature>
    </featureManager>

    <keyStore password="mypassword"/>

    <basicRegistry id="basic" realm="BasicRealm"> 
        <user name="username" password="mypassword"/>
    </basicRegistry>

    <httpEndpoint httpPort="9080" httpsPort="9443" id="defaultHttpEndpoint"/>

    <applicationManager autoExpand="true"/>

    <ssl id="defaultSSLConfig" trustDefaultCerts="true"/>

    <applicationMonitor updateTrigger="mbean"/>

    <webApplication id="test" location="test-0.0.1-SNAPSHOT.war" name="test"/>
</server>
Astonvish32
  • 179
  • 2
  • 11
  • 2
    What *exactly* is null in Test.java:18, `configuration.getProperties()` or `configuration` itself? You are saying it is the first, but have you double checked in debug? The reason I am asking is that I find it strange that a JAX-RS "resource" (the `Configuration`) is available for injection in a pure CDI bean (i.e. a bean with no `@Path` annotation). I haven't used this feature in JAX-RS though, so I may be very wrong. – Nikos Paraskevopoulos Apr 21 '20 at 07:09
  • @NikosParaskevopoulos yes, it is `configuration.getProperties()` and I have double checked this. Following the answer by @areus if I replace `Configuration` with `Application`, `configuration.getProperties()` doesn't return null but rather an empty map. Trust me I am quite puzzled with this. I am not sure if a JAX-RS resource are meant be injected in a pure CDI bean. Assuming that it cannot be injected in a pure CDI bean, then why does this work with Payara server? – Astonvish32 Apr 21 '20 at 10:12
  • Well, I find the behavior of both systems strange: OpenLiberty makes me wonder why is it injecting a `Configuration` but leaving it empty (or, anyway, inconsistent)? Payara is probably interpreting a gray area of the specs in its own (admittedly convenient, but non-portable) way (injecting a JAX-RS artifact into a "just CDI" bean). My opinion: **You will experience such discrepancies frequently, when in doubt read the specs; if something is not clear in the official specs, using it might cause portability issues, even between versions of the same server!** Good luck! – Nikos Paraskevopoulos Apr 21 '20 at 11:28
  • Yes, you are right! Following @areus update, I have read the spec and decided to format my code following the spec. This is has been a great lesson thank you both! – Astonvish32 Apr 21 '20 at 14:17

1 Answers1

2

On my initial answer I assumed it was OpenLiberty's fault, but according to the JAX-RS 2.1 spec, section 10.2.8 Configuration,

Both the client and the server runtime configurations are available for injection via @Context. These configurations are available for injection in providers (client or server) and resource classes (server only).

The spec doesn't mandate CDI beans to support specific JAX-RS @Context annotations, only resources and providers.

It seems that Payara goes beyond the spec, and supports the @Context annotation on CDI beans.

areus
  • 2,880
  • 2
  • 7
  • 17
  • Thank you for suggesting the use of `Application` instead of `Configuration`, this takes care of the error but `application.getProperties()` return an empty map. Note that if I inject either `Configuration` or `Application` into `TestResources.java` every thing works well. It be that OpenLiberty doesn't allow the use of `@Context` in a CDI managed bean. Also thanks for the tip with `ApiEntryPoint.java`. – Astonvish32 Apr 21 '20 at 10:03
  • You are right, I didn't notice that Test was not a JAX-RS class. The JAX-RS spec states that the Configuration can only be injected in resources or providers. Looks like Payara goes beyond that and supports JAX-RS specific injections on CDI beans. – areus Apr 21 '20 at 10:14
  • 1
    Thanks for the help. Next time that I have a contradiction between 2 servers, I will try to read the spec. Thanks! – Astonvish32 Apr 21 '20 at 10:46