How to Programmatically Inject a Java Cdi Managed Bean into a Local Variable in a (Static) Method

How to programmatically inject a Java CDI managed bean into a local variable in a (static) method

To inject an instance of class C:

javax.enterprise.inject.spi.CDI.current().select(C.class).get()

This is available in CDI 1.1+

Get a CDI bean dynamically, NOT by injection

I found the answer here:
How to programmatically inject a Java CDI managed bean into a local variable in a (static) method

Need to use:

javax.enterprise.inject.spi.CDI.current().select(C.class).get()

Programmatic run-time injection/auto-wiring in quarkus

This is similar to this question.
How to programmatically inject a Java CDI managed bean into a local variable in a (static) method

javax.enterprise.inject.spi.CDI.current().getBeanManager().select(C.class).get()

To make sure that the bean class is manged use the io.quarkus.arc.Unremovable annotation.

CDI for incoming JSON deserialised POJOs

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.

Injection of stateless session bean into custom JsonDeserializer fails

Jon Peterson pointed me to the right direction. I finally chose to implement the 'hackish' solution, in a way. Please note that there are basically 2 options here (if you know another one, please let me know!). Short version:

  1. Hackish solution (the solution I chose): inject a bean programmatically using javax.enterprise.inject.spi.CDI.current().select(UserFacadeRest.class).get() as described in the accepted answer of the question mentioned by Jon or
  2. Better (clean) solution (but also more elaborate): Redesign the logic to fill the missing fields after deserialization as suggested by Jon.

So for my question, the solution looks as follows:

1.

import javax.enterprise.inject.spi.CDI;

public class UserDeserializer extends JsonDeserializer<User> {

private final UserFacadeREST userFacade =
CDI.current().select(UserFacadeREST.class).get();

// Rest as before
}

2. In this case, in the deserialize method of my JsonDeserializer I would construct a User that just holds the userID. In every request method I would then have to examine all the users and replace them by the actual user by calling EntityManager.find(User.class, user.getUserID()). This means more effort in the business logic as you have to keep in mind that everytime you need to work on a User in a request method, you first have to do a query to get the 'full' User object. In the first solution, this query is hidden from the business logic and already happens in the JsonDeserializer.

public class UserDeserializer extends JsonDeserializer<User> {

@Override
public User deserialize(JsonParser parser, DeserializationContext context) throws IOException,
JsonProcessingException {
JsonNode node = parser.getCodec().readTree(parser);
int userId = (Integer) ((IntNode) node.get("userID")).numberValue();
return new User(userId); // Placeholder User object containing only the user ID, needs to be replaced in business logic
}

}


Related Topics



Leave a reply



Submit