I am trying DeltaSpike Data Module on Wildfly i followed the things mentioned in the document, when I try to run a Servlet having a Repository i am getting a NullPointerException while using the repository
#Inject
private OrdersRepository orderRep;
List<OrderDto> dao = orderRep.findByRetailer("MyRetail"); // NullPointer
Code
#Repository(forEntity = Order.class)
#MappingConfig(OrderMapper.class)
#EntityManagerConfig(entityManagerResolver = MyDBResolver.class)
public abstract class OrdersRepository extends AbstractEntityRepository<OrderDto, String> {
#Query(named = Order.ORDER_BY_RETAILER, max = 1)
public abstract List<OrderDto> findByRetailer(String retailer);
}
...
Am I missing anything here ?
Try adding #Dependent to your repository classes.
CDI 1.1 used in WildFly has implicit bean archives by default, i.e. candidate bean classes require a bean defining annotation.
Related
I am using JSF 2.3 and I want to inject different sublaccess of a session scoped bean as a managed property using CDI.
From the link below
How to inject different subclasses as ManagedProperty JSF 2?
I understood that this was not possible for RequestScoped beans using the "old" JSF and JEE-annotations, but my beans have session scope and I am using CDI injection, and therefore different annotations than the ones used in the above link.
In particular I do have:
public abstract class BaseContainer {
String prop1;
}
#Named
#SessionScoped
public class MaklerContainer extends BaseContainer {
String prop 2;
}
#Named
#SessionScoped
public class AppManagerContainer extends MaklerContainer {
String prop 3;
}
public abstract class BaseBean {
#Inject
#javax.faces.annotation.ManagedProperty(value = "#{maklerSessionContainer}")
private MaklerSessionContainer maklerSessionContainer;
}
Is it possible to inject interchangeably instances of both MaklerContainer and AppManagerContainer as a managed property maklerSessionContainer of the class BaseBean above?
Let me describe one option, there may be others.
First of all, if you want to inject different sublaccess, you have to find a way to disambiguate them for CDI, or it will complain about "Ambiguous dependencies". E.g. given the class hierarchy of the question, the line below results in ambiguous dependency exception, because CDI cannot decide whether to inject the MaklerContainer or the AppManagerContainer that extends it:
#Inject MaklerContainer maklerContainer; // ambiguous!
You can use qualifiers, named beans, or #Typed (perhaps there are even more ways).
Let's use #Named, since it is already present.
The idea is to create a producer that introduces a third bean of type MaklerContainer, with a different name, to the appropriate scope. The producer code will decide which of the 2 implementations to choose at runtime. Something like this:
#ApplicationScoped
public class TheProducer {
#Inject #Named("maklerContainer")
private MaklerContainer maklerContainer;
#Inject #Named("appManagerContainer")
private AppManagerContainer appManagerContainer;
#Inject
private User currentUser;
#Produces
#SessionScoped
#Named("theOne") // choose appropriate name of course
public MaklerContainer makeMaklerContainer() {
if (currentUser.hasRole("Role1")) {
return appManagerContainer;
} else {
return maklerContainer;
}
}
}
Now all you have to do is inject the appropriate named MaklerContainer, like:
#Inject #Named("theOne") MaklerContainer maklerContainer;
Given
public class BeanContainer {
#Produces
Bean bean = new Bean();
}
and its alternative:
#Alternative
public class BeanContainerAlt extends BeanContainer {
#Produces
int producerInt = 10;
}
where Bean is
public class Bean {
boolean didPostConstruct = false;
#PostConstruct
public void postConstruct() {
didPostConstruct = true;
}
}
injected into MainClass:
public class MainClass {
#Inject
Bean bean;
#Inject
Integer producedInt;
}
Then:
Weld weld = new Weld()
.disableDiscovery()
.addBeanClass(MainClass.class)
.addBeanClass(BeanContainer.class)
.addBeanClass(BeanContainerAlt.class)
.alternatives(BeanContainerAlt.class);
WeldContainer container = weld.initialize();
final MainClass mainClass = container.select(MainClass.class).get();
assertFalse(mainClass.bean.didPostConstruct);
assertEquals(10, (long)mainClass.producedInt);
BeanContainer containerObject = container.select(BeanContainer.class).get();
assertEquals(BeanContainerAlt.class, containerObject.getClass());
gives no error. I would have expected that Bean.class would have to be added using addBeanClass to be able to satisfy the inject in MainClass. The explanation is that the Superclass of BeanContainerAlt whose Producers should imO not be effective, produces the Bean-Object.
Is that behavior intended or even according to the spec (I did not find it), is it probably defined in the weld-documentation?
The sourcecode can be found in
examplesrc
mvn clean install -Dtest=ReproProducersInSuperclasses
in that project should make it run
Indeed, the fields and methods annotated with #Producer are not inherited - as discussed in the accepted answer to Why are Producers not inherited in CDI
However, according to the CDI specification:
5.1.2. Enabled and disabled beans
A bean is said to be enabled if:
(E1) it is deployed in a bean archive, and
(E2) it is not a producer method or field of a disabled bean, and
(E3) it is not specialized by any other enabled bean, as defined in Specialization, and either
(E4) it is not an alternative, or it is a selected alternative of at least one bean archive or the application.
Otherwise, the bean is said to be disabled.
According to these definitions and code above:
BeanContainer is not an alternative (E4) and therefore is enabled managed bean
BeanContainerAlt is a selected alternative (E4) and therefore is enabled managed bean
Bean and int are enabled because they are not a producer method or field of a disabled bean (E2), as BeanContainer and BeanContainerAlt are both enabled (E4)
Therefore producer fields in both BeanContainer and BeanContainerAlt are used to resolve dependencies.
The test fails as shown below when BeanContainer is not deployed (E1):
WELD-001408: Unsatisfied dependencies for type Bean with qualifiers #Default
at injection point [BackedAnnotatedField] #Inject
net.oneandone.iocunit.testalt.MainClass.bean
The test fails as shown below when BeanContainerAlt is not selected (E4):
WELD-001408: Unsatisfied dependencies for type Integer with qualifiers #Default
at injection point [BackedAnnotatedField] #Inject
net.oneandone.iocunit.testalt.MainClass.producedInt
In a Java EE 6, CDI 1.1.x, Seam 3 etc. environment, we need to find all CDI beans of the current view (#ViewScoped). What I have tried so far is using:
#Named
#ViewScoped
public class ViewHelper
{
#Inject
private BeanManager beanManager;
public doSomethingWithTheBeanInstances()
{
Set<Bean<?>> beans = this.getBeanManager().getBeans(
Object.class, new AnnotationLiteral<Any>(){}
);
// do something
...
}
}
However, this returns all beans it manages.
I need to find only those within the scope of the current view and - that would be ideal - only those that implement a specific interface (inherited over over multiple hierarchy levels).
What's the way to do it?
Note since CDI has no view scope, we're using Seam 3 to be able to annotate all our view-scoped beans like:
#Named
#ViewScoped
public class ResultManagerColumnHandler extends BaseColumnHandler
{
....
}
The above would be an instance to look for (the #ViewScoped is a CDI replacement by Seam 3).
How can it be done?
I am not familiar with Seam, but from CDI standpoint, this is what I would try. However, bean it mind that it will only work if beanManager.getContext(ViewScoped.class); returns a valid context instance for you:
#Inject
BeanManager bm;
public List<Object> getAllViewScoped() {
List<Object> allBeans = new ArrayList<Object>();
Set<Bean<?>> beans = bm.getBeans(Object.class);
// NOTE - context has to be active when you try this
Context context = bm.getContext(ViewScoped.class);
for (Bean<?> bean : beans) {
Object instance = context.get(bean);
if (instance != null) {
allBeans.add(instance);
}
}
return allBeans;
}
You also asked to only obtain beans that implement certain interface. For that, simply modify the code line retrieving all beans with desired type:
Set<Bean<?>> beans = bm.getBeans(MyInterface.class);
I have the following classes:
#Named
#ViewScoped
public class BaseClass {
private SomeDependency dep;
public BaseClass(){}
#Inject
public BaseClass(SomeDependency dep) {
this.dep = dep;
}
#PostConstruct
private void initialize() {
dep.doSomething(); // Point "A"
}
public String getProperty() {
return "BaseClass-Property";
}
#Specializes
public class SpecialClass extends BaseClass() {
#Override
public String getProperty() {
return "SpecialClass-Property";
}
}
Now in some .xhtml I have something like
<h:outputText value="#{baseClass.property}" />
This works fine without the SpecialClass. It breaks with a NullPointerException at Point "A" if I include the SpecialClass in the project.
Well, according to the Weld specification, this is more or less intended behavior:
When an enabled bean specializes another bean, the other bean is never
instantiated or called by the container.
Nevertheless, now I have to make sure that every #Specializes bean implements the complete constructor like
public SpecialClass() {}
#Inject
public SpecialClass(SomeDependency dep) { super(dep); }
which IMHO is kind of counter-intuitive and produces a lot of duplicated, boilerplate code, especially with something like 5-6 arguments for every constructor. Also, this is never caught when creating a new specialized bean since the project is always still compile clean.
Am I doing something wrong or is there no alternative to implementing the constructors over and over again?
BTW, I do use Constructor Injection to create easily testable classes where I can just use the constructor to "Inject" dummy implementations of the dependencies.
CDI 1.1 spec at section 4.3 says:
"The only way one bean can completely override a second bean at all
injection points is if it implements all the bean types and declares
all the qualifiers of the second bean."
Your base class is annotated with the Named qualifier and the specializing class is not. You should also mark it with Alternative and enable it in beans.xml. There's also the ViewScoped annotation. Unless it's the Omnifaces' ViewScoped, it looks like you're mixing up JSF managed beans with CDI beans.
This is in relation to the workaround for the known issue of JSF FacesConverter not being an eligible #Inject target for CDI. I followed the workaround at CDI Injection into a FacesConverter. However, in my FacesConverter, I had been utilizing the feature of having the Class of the object passed into a constructor.
From the javadoc - "If a converter has a single argument constructor that takes a Class instance and the Class of the data to be converted is known at converter instantiation time, this constructor must be used to instantiate the converter instead of the zero-argument version." This is in direct conflict with the CDI requirement for "normal scope" beans where a no-arg or #Inject annotated constructor is all that's allowed.
So in summary, I want to use a Converter that can take CDI Injections, and has access to the Class of the object being converted at runtime.
I am using Mojarra 2.2.4 on Glassfish 4 with Weld 2.0.4.
For those who might be interested in this alternative, I was able to replace the Inject annotations with programmatic lookup via BeanManager in the constructor. The condensed code is below. I've not performance tested, and suspect that may be a downside. If time permits I'll compare to the Omnifaces solution.
EDIT: The cost of the BeanManager lookup turned out to be minimal. The constructor takes on average <1ms.
#FacesConverter(forClass = AbstractEntity.class)
public class EntityConverter implements Converter {
private LocationService locationService;
private Class entityClass;
//Special parameterized constructor for #FacesConverter described in the original question
public EntityConverter(Class entityClass) throws NamingException {
this.entityClass = entityClass;
this.locationService = loadManagedBean(LocationService.class, "locationService");
}
//Generic lookup method for #Named managed beans
protected <T> T loadManagedBean(Class<T> clazz, String beanName) throws NamingException {
InitialContext initialContext = new InitialContext();
BeanManager bm = (BeanManager) initialContext.lookup("java:comp/BeanManager");
Bean<T> bean = (Bean<T>) bm.getBeans(beanName).iterator().next();
CreationalContext<T> cc = bm.createCreationalContext(bean);
T beanInstance = (T) bm.getReference(bean, clazz, cc);
return beanInstance;
}
}