Here's what I've got:
#Component
class FooController {
fun createFoo() {
val foo = FooEntity()
foo.name = "Diogo"
fooRepository.save(foo)
}
#Autowired
internal lateinit var fooRepository: FooRepository
}
When trying to call createFoo(), I get the following error:
kotlin.UninitializedPropertyAccessException: lateinit property fooRepository has not been initialized
I thought that adding a #Component at the top would make my class discoverable by Spring and hence make #Autowired work, but maybe I got it wrong?
Just adding #Component to the class is not enough.
1) When you use #Component you have to make sure that the class is scanned by a component scan. It depends on how you bootstrap your applciation, but you can use <context:component-scan base-package="com.myCompany.myProject" /> for XML config or #ComponentScan for java configuration.
If you're using Spring boot - you don't need to declare #ComponentScan yourself, because #SpringBootApplication inherits it and by default it scans all the classes in the current package and all it's sub packages.
2) You have to get the bean from the spring context. Creating an object with new will not work.
Basically there are two ways to get a bean from the application context:
If you have an access to the ApplicationContext object then you can do something like this:
ApplicationContext ctx = ...;
MyBean mb = ctx.getBean(MyBean.class);//getting by type
Any spring bean that's declared in the context can access the other beans using dependency injection (#Autowired)
So I'm very new to Spring and was trying to call FooController by creating a instance of it through new instead of #Autowireing everywhere. When I added FooController as a dependency of the class it was being called from, it worked.
Related
I defined an interface.
#Local
public interface MessageService {
}
And an implementation.
#Stateless
public class MessageServiceSome implements MessageService {
}
When I tried to inject it into my resource class, I got null.
//#Path("/messages") // I'M NOT GOING TO MAKE THIS STATELESS!!!
public class MessagesResource {
// none of follwoing options works
// leaves the field null
#Inject
//#EJB
//#EJB(beanName = "MessageServiceSome")
private MessageService messageService;
}
How can I solve this?
UPDATE
I think I have to admit that my question is not good enough.
The MessagesResource class was actually a sub resource. I didn't know the difference.
There are two very good threads for this issue.
https://stackoverflow.com/a/36291890/330457
https://stackoverflow.com/a/24670218/330457
One is using ResourceContext and the other is using Inject.
Both threads are saying they work but I only succeeded with #Inject.
With little information provided, you have probably two quick options you can try:
leave #Inject only, if your project/container is CDI enabled
#Inject
private MessageService messageService;
leave #EJB only, do you really need the beanName ?
#EJB
private MessageService messageService;
on of the two should solve the issue.
[UPDATE]
Otherwise have a look at the app server start up log, and see if the bean has been deployed.
While having a custom qualifier for CDI support as followed:
#Qualifier
#Retention(RUNTIME)
#Target({METHOD, FIELD, PARAMETER, TYPE})
public #interface QualifiedFooBean {
}
#QualifiedFooBean
public class FooBean implements ImplFooBean {
}
public interface ImplFooBean {
}
I would like to bind FooBean #{fooBean} directly without requiring a wrapper or processor (seen from this example). The annotation "Named" (in class FooBean) seems not to work for my class layout.
My solution (without wrapper) which I'm wondering why it's not working and invoking: Target Unreachable, identifier 'fooBean' resolved to null
#Named
#QualifiedFooBean
public class FooBean implements ImplFooBean {
}
Has anyone any idea?
A wrapper is not needed. My solution is perfectly valid. It's also allowed to add Named in combination of a custom qualifier (in my case QualifiedFooBean). I had to just create an empty beans.xml file in WEB-INF folder in order to get CDI to work. Anyhow The question itself explains how custom qualifiers can work. You can also prefill beans.xml with following content:
<beans xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
</beans>
It will serve as a skeleton for future use, if you need to configure more fancy stuff with CDI.
Adding #Named to your bean should work : it works for me.
In Fact #Named is a qualifier, when JSF resolve the Bean for displaying it does a lokup based on #Named qualifier. In CDI a bean is found if the lookup side (i.e. Injection point) ask for a subset of its Qualifier.
For instance a bean qualified like that :
#QualifiedFooBean
#SecondQualifier
public class FooBean {}
Will be found (if there is no ambiguous resolution) by
#Inject
#SecondQualifier
FooBean bean;
or even :
#Inject
FooBean bean;
But not by
#Inject
#SecondQualifier
#ThirdQualifier
FooBean bean;
So you can add the #Named qualifier and let CDI resolution engine do its job.
I've been searching here about it, but haven't found an answer.
In my application, I've an abstract main class for my controllers, with some methods and properties. And I want to inject the DAO automatically.
abstract class AbstractController<E extends AbstractEntity, D extends AbstractDAO<E>> {
#Inject
private D dao;
// getters and setters
}
abstract class AbstractDAO<E extends AbstractEntity> {
#PersistentContext
private EntityManager em;
// finds returns E
}
// implemenation/usage
class CarController extends AbstractController<Car, CarDAO> {
}
Getting the exception:
org.jboss.weld.exceptions.DefinitionException: WELD-001407 Cannot declare an injection point with a type variable: [field] #Inject private AbstractController.dao
Using: Glassfish 3.1 and JSF 2.1.
Is there a workaround or alternative for this?
Thanks.
It's technically very complicated for reflection to detect the proper runtime type by a generic declaration in the source and cast to it. Weld simply don't and won't support it.
Better declare it against AbstractDAO<E>:
private AbstractDAO<E> dao;
You gain nothing with declaring it against D anyway.
I'm a little confused with #RunWith(MockitoJUnitRunner.class) and #InjectMock annotations and how they are related to each other. As per my understanding by giving #RunWith(MockitoJUnitRunner.class) we don't need to initialize the mock like mock(ABC.class).
On the other hand #InjectMocks injects the mock automatically with getters and setters. The documentation says:
#InjectMocks currently it only supports setter injection. If you prefer constructor injection - please contribute a patch....
What I don't understand is that when I remove #InjectMocks below I get nullpointer exception for the tests as dependency is null. Does that mean construtor based inject is supported? Or does it has something to do with #RunWith(MockitoJUnitRunner.class)
Here's the code
#RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
#Mock
private Dependency dependency;
#InjectMocks
private MyClass cls = new MyClass(dependency);
//...
}
class MyClass {
private Dependency dependency;
MyClass(Dependency dependency) {
this.dependency = dependency;
}
//...
}
As of the latest release, Mockito supports constructor injection.
See the latest javadoc.
From just a few searches, this seems like a problem that has been around for a while. I have written a FacesConverter that looks like the following. The object Category is a JPA entity and CategoryControl is the DAO that fetches it.
#FacesConverter(value = "categoryConverter")
public class CategoryConverter implements Converter {
#Inject private CategoryControl cc;
public CategoryConverter() { }
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (cc != null) return cc.getByName(value);
System.out.println("CategoryConverter().getAsObject(): no injection!");
return null;
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (!(value instanceof Category)) return null;
return ((Category) value).getName();
}
}
As you probably guessed by now, I never get the injection. I got this workaround from this page, which looks like this.:
Workaround for this problem: create this method in your localeController:
public Converter getConverter()
{
return FacesContext.getCurrentInstance().getApplication().createConverter("localeConverter");
}
and use converter="#{localeController.converter}" in your h:selectOneMenu.
However I can't make this work either. My backing bean creates and returns a converter all right, but it doesn't get the object injected into it.
I am using MyFaces CODI 1.0.1. With the current GlassFish/Weld container. Can anyone suggest a solution before I re-code to not use a Converter?
Replace
#FacesConverter(value = "categoryConverter")
by
#Named
and use
<h:inputSomething converter="#{categoryConverter}" />
or
<f:converter binding="#{categoryConverter}" />
instead of
<h:inputSomething converter="categoryConverter" />
or
<f:converter converterId="categoryConverter" />
By the way, similar problem exist for #EJB inside a #FacesConverter. It however offers a way to be grabbed by JNDI manually. See also Communication in JSF 2.0 - Getting an EJB in #FacesConverter and #FacesValidator. This way you can use a #FacesConverter(forClass=Category.class) without manually defining it everytime. Unfortunately I can't tell from top of head how to realize that for CDI beans.
Update: if you happen to use JSF utility library OmniFaces, since version 1.6 is adds transparent support for using #Inject and #EJB in a #FacesConverter class without any additional configuration or annotations. See also the CDI #FacesConverter showcase example.
The #Inject Annotation only works in CDI managed instances. If you want to use CDI features inside a non-CDI managed instance (Like a JSF Validator or a JSF Converter) you can just programm against the CDI API.
This works only in at least Java EE 7 + CDI 1.1 server.
#FacesValidator("userNameValidator")
public class UserNameValidator implements Validator {
private UserService userService;
public UserNameValidator(){
this.userService = CDI.current().select(UserService.class).get();
}
#Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
....
}
}
https://docs.oracle.com/javaee/7/api/javax/enterprise/inject/spi/CDI.html
With all the AnnotationHell in Java EE people forget how to code.
Just use #Advanced of CODI for your #FacesConverter see the Wiki.
As soon as a converter or a validator is annotated with #Advanced it's possible to use #Inject.
Per BalusC's answer here, I decided to add JSF (requestscoped) managed beans that only contained #FacesConverter and Converter to resolve this issue in my app, since I'm migrating from JSF managed beans to CDI managed beans.
I tried CODI #Advanced against #FacesConverter, but it does not inject the bean at all.