How can I create a producer method that creates an object depending on a parameter?
My goal is to being able to inject a CrudService on different classes in my application, but to parametrize it with the class for which the service is used for (eg. User.class).
The following code does of course not work, but illustrates my intention.
#Produces
#JPAContainer(Class type) //something like this?
public JPAContainer getJPA() {
#PersistenceContext
private EntityManager em;
#Produces
#JPAContainerAnnot
public JPAContainer getJPAContainer() {
return JPAContainerFactory.make(type, em); //eg: class = User.class, Person.class
}
}
#Stateless
public class CrudServiceUser() {
#Inject
#JPAContainer(type = User.class) //something like this parameter
private JPAContainer container;
}
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target({FIELD,METHOD,PARAMETER,TYPE})
public #interface JPAContainer {
}
Yes, you can inject the InjectionPoint object in to your producer method. the type attribute of your qualifier needs to be #Nonbinding. From the InjectionPoint you can get reference to the annotations on the injection point, find your JPAContainer and read the values from it.
Related
I've got a Factory class in Java with some methods which return some Java Bean. All of these Java Beans have some DAO object as fields which are injected with the annotation #EJB. However in every case these DAO are all Null, so I suppose I've a problem with EJB injection. I use WebLogic for deploy. Any suggestions to resolve the issue?
//Factory class
public class Factory extends AbstractFactory {
#Override
public InterfaceService getService() {
return new ClassBean();
}
}
//Bean class
#Stateless(mappedName = "ClassBean")
#LocalBean
public class ClassBean implements IBeanService {
#EJB(beanName = "ClassDAO")
private ClassDAO classDAO;
public List<String> getList() throws ExpectedModelException {
return classDAO.getStringList(); //this one throws NullPointerException
}
Never create Enterprise-Beans using new.
The creation, caching, deletion,... is done by the container.
You must declare ClassDao as #Stateless or #Singleton, ... and the container will create and find it, hopefully if the names are correct.
The Factory is not necessary.
I defined some interfaces with generic, and I have some classes injected in Spring context as Beans, could I dynamic create a manager bean to manage them, and it could be autowired in fields without any Bean def code of this manager?
I have tried FactoryBean way to implement it, but not worked, it couldn't transmit generic class info and the FactoryBean bean couldn't transmit any changable arguments.
I have tried BeanFactory way to implement it, when I getBeansOfType, these objects created without autowired, not worked...
Now I have a finally method which I think it's not very smart that is using ImportBeanDefinitionRegistrar and ClassPathBeanDefinitionScanner to scan all classes, then insert the manager's beanDefinition.
I'll be very appreciate if you supply any method, Thank you very much !
I want to implement it like this:
public interface Strategy<E extends BaseEnum>
{
public E getType();
}
public interface LoginStrategy extends Strategy<LoginType>
{
public LoginStrategy getType();
}
#Strategy
public class ALoginStrategy implements LoginStrategy
{
public getType()
{
return LoginType.OTP;
}
}
#Strategy
public class BLoginStrategy implements LoginStrategy
{
#Autowired
private UserMapper;
public getType()
{
return LoginType.PASSWORD;
}
}
public LoginServiceImpl implements LoginService
{
#Autowired
private StrategyManage<LoginType, LoginStrategy> strategyManager;
}
I want the strategyManager in LoginServiceImpl which is marked Autowired could be auto generated.
I also have a other question. It may be easier to explain what I want.
I have a model convertor implements a ModelConvertor interface, TL is lowerModel's class, TU is upperModel's class.
now there is a bean include code like this:
#Autowired
private ModelConvertor<UserPO, UserDO> userConvertor;
normally Spring frame would throw a Exception with a "no such bean" message, so I want to make this field could auto inject a value like this:
#Autowired
private ModelConvertor<UserPO, UserDO> userConvertor[ = new DefaultModelConvertor(UserPO.class, UserDO.class)];
How can I do to solve these problems, thanks a lot again!
I have resolved this problem, scan specific packages and dynamic generate beans to put on context.
I am trying to autowire a member in a class using the constructor.
#Component
public class MyClass {
private ClassA myMember;
#Autowire
public MyClass(ClassA objectA) {
myMember = objectA;
}
}
If I have multiple sources that create beans of ClassA, is it possible to have a duplicate constructor definition that instantiates based on the bean that was autowired into this class?
I want to do something like this:
#Component
public class MyClass {
private ClassA myMember;
#Autowire
public MyClass(#Qualifier ("qualifierA") ClassA objectA) {
myMember = objectA;
}
#Autowire
public MyClass(#Qualifier ("qualifierB") ClassA objectB) {
myMember = objectB;
}
}
I tried using #Qualifier this way, but it didn't work.
Is it possible to do what I'm trying to do, with Spring? How can I disambiguate based on the name (qualifierA) or (qualifierB), if the bean definition is like:
#Bean (name = "qualifierA")
public ClassA getQualifierA() {
...
}
#Bean (name = "qualifierB")
public ClassA getQualifierB() {
...
}
You can't have two constructors with the exact same signature in a single class in Java. Nor any other programming language I've ever encountered. You might use method-injection instead, with two methods (named differently, of course), mark them as #Autowired(required = false) and use the proper #Qualifier(...) to specify the instance you want to inject. You might want to handle the case when both instances are present in the spring context, so no unexpected things happen.
The short answer is: no, that is not possible. In Java you cannot have two constructors with exactly the same signature. And also, you can assign only one value to your "myMember".
However, what are you trying to accomplish here? It seems that in some occasions MyClass needs to use "objectA" and in other occasions, you need "objectB".
For these scenarios, you should not use autowiring (you can't), but simply use explicit wiring:
#Bean
MyClass myObject() {
return new MyClass(qualifierA());
}
I have read about the #Produces annotation in CDI, but I don't understand its usage.
public class Resources {
// Expose an entity manager using the resource producer pattern
#SuppressWarnings("unused")
#PersistenceContext
#Produces
private EntityManager em; //
#Produces
Logger getLogger(InjectionPoint ip) { //
String category = ip.getMember()
.getDeclaringClass()
.getName();
return Logger.getLogger(category);
}
#Produces
FacesContext getFacesContext() { //
return FacesContext.getCurrentInstance();
}
}
taken from: http://www.jboss.org/jdf/quickstarts/jboss-as-quickstart/guide/GreeterQuickstart/#GreeterQuickstart-
How does the container know to call a producer method? If I inject an EntityManager, how does the container call the #produces EntityManager? And how would a getLogger producer method get called?
I also don't see the reason to go through all of the trouble.
Section 3.3 of the CDI specification gives a pretty good high level overview of the use of the #Produces annotation:
A producer method acts as a source of objects to be injected, where:
• the objects to be injected are not required to be instances of beans, or
• the concrete type of the objects to be injected may vary at runtime, or
• the objects require some custom initialization that is not performed by the bean constructor.
Let's say, for example, that you wanted to bridge between a Java EE managed component like an entity manager and other CDI components, you could utilize the #Produces annotation. Another benefit being that you avoid having to duplicate #PersistenceContext annotations throughout your data domain layer.
class A {
#PersistenceContext // This is a JPA annotation
#Produces // This is a CDI 'hook'
private EntityManager em;
}
class B {
#Inject // Now we can inject an entity manager
private EntityManager em;
}
Another handy use is for getting around libraries that do not have CDI friendly beans (for example, no default constructors):
class SomeTPLClass {
public SomeTPLClass(String id) {
}
}
class SomeTPLClassProducer {
#Produces
public SomeTPLClass getInstance() {
return new SomeTPLClass("");
}
}
The Javadoc for produces also shows an interesting (but fairly rare case) of producing a named collection that can later on be injected into other managed beans (very cool):
public class Shop {
#Produces #ApplicationScoped
#Catalog #Named("catalog")
private List<Product> products = new LinkedList<Product>(8);
//...
}
public class OrderProcessor {
#Inject
#Catalog
private List<Product> products;
}
The container is responsible for processing all methods and fields marked with a #Produces annotation, and will normally do this when your application is deployed. The processed methods and fields will then be used as part of the injection point resolution for managed beans, as needed.
The example didn't quite work for me. What dit work was a minor tweak:
#Alternative
class SomeTPLClass {
public SomeTPLClass(String id) {
}
}
class SomeTPLClassProducer {
#Produces
public SomeTPLClass getInstance() {
return new SomeTPLClass("");
}
}
So i had to add #Alternative on my class to get rid of the error that there were two options for #Default.
I'd like to be able to #Inject a data model backing a RichFaces 4 ExtendedDataTable, but it requires an EntityManager to do its work. The EntityManager's queries need to know the Class, of course, and I'd rather not pass that into method calls (in this case the methods are not called by my code); ideally it would be in the constructor.
Something like this:
public class DataModel<T> {
#Inject private EntityManager em;
private Class<T> entityClass;
public DataModel(Class<T> entityClass) {
this.entityClass = entityClass;
}
//Sample method - this class will handle much more complex queries
public T findEntity(String key) {
return em.find(entityClass, key);
}
Is it possible to create a CDI #Producer that can be used to inject this DataModel into my backing beans? I've thought about making a Qualifier so you can do something like
#Inject #JType(value = MyEntity.class) DataModel<MyEntity> dataModel;
But that seemed clumsy, and would also require my #Producer to call new() - which I think would not allow the EntityManager to be injected into the DataModel. Also I'm not sure how you would require the qualifier to be added by the developer.
Or perhaps there's a better way to approach this, and I'm missing something?
I do this using the seam-persistence module from seam3. :
Producer :
public class EntityManagerProducer {
#Produces
#ExtensionManaged
#ConversationScoped
#PersistenceUnit(unitName = "yourUnitName")
private EntityManagerFactory emf;
}
Then you can #Inject the entity manager.
Otherwise, there is the DeltaSpike project that seems promising (never used it yet)