Caroline
Caroline

Reputation: 920

Pass runtime arguments to Object containing Injections

Context:

Based on an XML my Java EE application receives, I want to make a new AreeConfiguration object in which Injection of 3 objects happens. The selection of a correct Instance<> happens based on information in this XML. Therefore, I am passing around information from this XML.

I have a datastructure which should be filled with these AreeConfiguration objects at runtime:

private HashMap<Integer, AreeConfiguration> configurations = new HashMap<Integer, AreeConfiguration>();

public void parseNewConfiguration(Element el) throws InvalidDescriptorException {
    if(!isValidConfiguration(el)) throw new InvalidDescriptorException();

    int key = getUniqueKey();

    AreeConfiguration cfg = new AreeConfiguration(key, el);       
    configurations.put(key, cfg);
}

My AreeConfiguration object should (ideally) be constructed with the essential XML information and Inject some objects. Later, I want to use the information from the XML to pick the right Instance<>.

public class AreeConfiguration {

@Inject
private Instance<AreeInput> ais;
private AreeInput ai;

@Inject
private Instance<AreeReasoner> ars;
private AreeReasoner ar;

@Inject
private Instance<AreeOutput> aos;
private AreeOutput ao;

AreeConfiguration(int key, Element el) throws InvalidDescriptorException {
    ...
}   

@PostConstruct
public void chooseComponents(){     
    ai = chooseInput();
    ar = chooseReasoner();
    ao = chooseOutput();
}

What I have found and tried:

Through research (here at Stack Overflow), I now understand that CDI does not Inject in objects that have been created with new Object(). The code displayed above, never enters chooseComponents().

When I want to try using an @Producer, I annotate parseNewConfiguration(Element el) with @Producer and add an @New AreeConfiguration cfg argument. However, then I cannot pass the Element el too, which is unfortunate because it contains the essential XML information.

Please ask additional questions if I did not explain myself thoroughly. I am looking for a way to accomplish the above using CDI.

Additionally, how 'clean' is the solution proposed in the answer of this question: @Inject only working for POJOs created by CDI container?

Upvotes: 3

Views: 879

Answers (3)

Caroline
Caroline

Reputation: 920

In this particular case, dynamic injections only need to take place after a client's call. Therefore, I am now simply injecting what I need in my WebService. When a client calls the WebService, an injection automatically takes place.

@Path("newconfiguration")
@RequestScoped
public class NewConfigurationResource {

@Context
private UriInfo context;

@Inject
private AreeConfiguration injConfig;

public NewConfigurationResource() { }

@POST
@Path("post")
@Produces("application/json")
public Response postJson() {
    ...
    doSomething(injConfig);
    ...
} 

Upvotes: 1

Ken
Ken

Reputation: 835

To perform injection into instances that were not created by a CDI container, and you have access to the BeanManager, then you can do something like:

// Create a creational context from the BeanManager
CreationalContext creationalContext = beanManager.createCreationalContext(null);

// Create an injection target with the Type of the instance we need to inject into
InjectionTarget injectionTarget = beanManager.createInjectionTarget(beanManager.createAnnotatedType(instance.getClass()));

// Perform injection into the instance
injectionTarget.inject(instance, creationalContext);

// Call PostConstruct on instance
injectionTarget.postConstruct(instance);

An example of a class that can be used to do all the work is at: http://seamframework.org/Documentation/HowDoIDoNoncontextualInjectionForAThirdpartyFramework.

Upvotes: 1

John Ament
John Ament

Reputation: 11723

You are generally correct, at most you can pass in some finite data types to CDI to create objects - namely primitives, static types, Strings, enums in to your qualifiers. This is a limitation of annotations. One thing I don't quite understand with your structure is why the client is passing all of this to you. This makes your code much more fragile and the client and server more tightly coupled. Couldn't you pass around some ID that represented a certain configuration? You still have the issue of not being able to pass around an XML element. You could pass around a string and have that available in a producer method's InjectionPoint.

Upvotes: 0

Related Questions