I'm using Payara Microservice for a Java web application and want to inject a bean into my deserialised JSON object so that I can add perform some additional logic.
So far I have the resource class, annotated with @Path and @POST, which I call via Postman with some JSON. The method invokes fine, however no matter what I try, I am unable to get the bean to inject.
The JSON object's class that looks like this:
public class IncomingJsonRequest {
@NotNull
private String value;
private AdditionalLogicClass additionalLogicBean;
public String setValue(String value) {
this.value = value;
}
public void performAdditionalLogic() {
additionalLogicBean.performLogic(value);
}
}
What I would like to do is inject the AdditionalLogicClass
bean so that when I call the performAdditionalLogic()
method from the resource method it doesn't throw a null pointer exception.
I've tried all sorts of annotations and so far the only way I can seem to do this is for the resource class to pass the bean in, but that's not good encapsulation. I don't want the resource to know about how this additional logic is done.
The other way was programatically loading the bean but I've read that it's not good practice.
What is the best way to achieve this?
Thanks
Using a programmatical CDI approach you can achieve it with the following:
@Path("sample")
public class SampleResource {
@POST
@Consumes(MediaType.APPLICATION_JSON)
public Response message(MyPayload myPayload) {
return Response.ok(myPayload.getName()).build();
}
}
A sample business logic CDI bean
public class BusinessLogic {
public String doFoo(String name) {
return name.toUpperCase();
}
}
The payload:
public class MyPayload {
private String name;
private BusinessLogic businessLogic;
public MyPayload() {
this.businessLogic = CDI.current().select(BusinessLogic.class).get();
}
public String getName() {
return businessLogic.doFoo(this.name);
}
public void setName(String name) {
this.name = name;
}
}
and finally the beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
bean-discovery-mode="all">
</beans>
Hitting the endpoint returns the expected input as uppercase:
curl -v -d '{"name": "duke"}' -H 'Content-Type: application/json' http://localhost:9080/resources/sample
< HTTP/1.1 200 OK
< X-Powered-By: Servlet/4.0
< Content-Type: application/octet-stream
< Date: Thu, 02 Jul 2020 06:16:34 GMT
< Content-Language: en-US
< Content-Length: 4
<
* Connection #0 to host localhost left intact
DUKE
This way you inject the CDI bean in the default constructor which is called by JSON-B when it tries to serialize the incoming payload.
The other way was programatically loading the bean but I've read that it's not good practice.
Not sure if there is any other solution to make this happen and let the CDI container take care of the injection.