Constructor injection preventing custom resource processing - java

In my (non-trivial) Spring Boot 1.5.4 application with Spring Data REST and HATEOAS leveraging Spring websockets, I have some custom resource processors, some custom controllers, and some custom repositories. Sadly, when I use constructor injection in one particular Spring #Service class for a MessageSendingOperations dependency, my custom resource processors no longer get invoked. Reverting the constructor injection restores the execution of my custom resource processors, i.e. reverting from:
private final MessageSendingOperations<String> messageTemplate;
#Autowired
public ChannelHandler(MessageSendingOperations<String> messageTemplate) {
this.messageTemplate = messageTemplate;
}
to:
#Autowired
private MessageSendingOperations<String> messageTemplate;
"re-enables" my custom resource processors which results in a null messageTemplate. So, there's a problem somewhere...but where??? Any ideas how to track this down?

Have you tried making messageTemplate a lazily injected proxy? For example:
public ChannelHandler(#Lazy MessageSendingOperations<String> messageTemplate) {
this.messageTemplate = requireNonNull(messageTemplate, "messageTemplate");
}
From the Javadoc:
In addition to its role for component initialization, this annotation
may also be placed on injection points marked with Autowired or
Inject: In that context, it leads to the creation of a lazy-resolution
proxy for all affected dependencies, as an alternative to using
ObjectFactory or Provider.
This usually affects the initialization order of your beans, in this case allowing ChannelHandler to be initialized before MessageSendingOperations. Without #Lazy, MessageSendingOperations will be initialized first.
Also: as of Spring 4.3, #Autowired is no longer required for single argument constructors.
+1 for using constructor injection and final fields.

Related

Build-time validation of web sockets ClientEndpoint in Quarkus

I use Java WebSocket API to declare client (Java class annotated by #ClientEndpoint):
#ClientEndpoint
public class MySock {
MySock(ExecutorService exec){}
...
}
Instance is created via constructor:
webSocket = new MySock(exec);
session = wsContainer.connectToServer(webSocket, url);
And I have error during the build via quarkus-maven-plugin:
[error]: Build step ...ArcProcessor#validate threw an exception:
javax.enterprise.inject.UnsatisfiedResolutionException:
Unsatisfied dependency for type ...ExecutorService and qualifiers [#Default]
- java member: edu.MySock#<init>()
- declared on CLASS bean [types=[edu.MySock, java.lang.Object], qualifiers=[#Default, #Any], target=edu.MySock]
Pay attention: there is no #Inject annotation
Should have it been validated, if it can be passed to #connectToServer as a class and as instance too?
So, Is it ok if validation processes a pessimistic case, where validation is useful, but it brokes an optimistic case?
Pessimistic case, where dependencies may not be declared:
session = wsContainer.connectToServer(MySock.class, url);
In the following case, validation is harmful because it brokes build phase:
session = wsContainer.connectToServer(webSocket, url);
Maybe ClientEndpoint should not be validated at all?
And before you ask me...
We are not going to inject something into WebSocket and we would not like to use programmatic EndPoints. But we want to create an instance for the annotated class. Why not? WebSocket incapsulates complex logic inside itself and this variant we used multiple times (e. g. in applications on WildFly).
The best solution for me would be to disable validation for my bean only, but I cannot find an idea of how to do it.
This article has not helped me https://quarkus.io/guides/cdi-reference. The fact that beans.xml is ignored cannot help me too.
The second-way, for the future, is to disable validation if there is no one class member with #Inject annotation. It can be not correct, but here there is some explanation:
First, the container calls the bean constructor (the default constructor or the one annotated #Inject), to obtain an instance of the bean.
So, my constructor is not "default" and I did not use #Inject annotation.
Work around is so simple: #javax.enterprise.inject.Vetoed annotation disables bean for validation.

Java Guice: If you inject the same dependency multiple times, is the same instance of that dependency injected?

I have a java jersey 2.x project, using Guice as my dependency injection framework. I have this service
public class AccountService {
private final AccountRepository accountRepository;
#Inject
public AccountService(InMemoryAccountRepositoryImpl inMemoryAccountRepositoryImpl) {
this.accountRepository = inMemoryAccountRepositoryImpl;
}
Let's say that I create another service class that also injects InMemoryAccountRepositoryImpl, will the same instance be injected? It's important for me to know, because this instance has an internal state that needs to be consistent.
By default, Guice returns a new instance each time it supplies a value. This behaviour is configurable via scopes. Scopes allow you to reuse instances: for the lifetime of an application (#Singleton), a session (#SessionScoped), or a request (#RequestScoped). Guice includes a servlet extension that defines scopes for web apps. Custom scopes can be written for other types of applications.
for more info see the documentation

Spring Custom Converter - To Bean or Not to Bean

I am implementing Custom Converter in Spring so my beans can convert from java.util.Date to java.time.LocalDateTime. I have implemented Converter already (by implementing Spring Converter interface)
Here is bean definition in #Configuration class
#Bean
ConversionService conversionService(){
DefaultConversionService service = new DefaultConversionService();
service.addConverter(new DateToLocalDateTimeConverter());
return service;
}
My question is : shall I pass my custom converter as Java Object or Spring Bean to service.addConverter?
In general what are the guidelines (criterias) whether to bean or not to bean in such scenarios?
Making an object a Spring Bean makes sense as you want that this object may benefit from Spring features (injections, transaction, aop, etc...).
In your case, it seems not required.
As conversionService is a Spring bean singleton that will be instantiated once, creating during its instantiation a plain java instance of DateToLocalDateTimeConverter seems fine : new DateToLocalDateTimeConverter().
Now, if later you want to inject the DateToLocalDateTimeConverter instance in other Spring beans, it would make sense to transform it to a Spring Bean.
For information Spring provides already this utility task in the Jsr310Converters class (included in the spring-data-commons dependency) :
import static java.time.LocalDateTime.*;
public abstract class Jsr310Converters {
...
public static enum DateToLocalDateTimeConverter implements Converter<Date, LocalDateTime> {
INSTANCE;
#Override
public LocalDateTime convert(Date source) {
return source == null ? null : ofInstant(source.toInstant(), ZoneId.systemDefault());
}
}
...
}
You could directly use it.
If you intend to inject this as a dependency of some kind into your application, and/or you intend to reuse it in multiple places, then it makes sense to register it as a bean. If you're not, then newing an instance up is acceptable.
Dependency injection and inversion of control are just that - how you inject dependencies into your app, and an acknowledgment that you no longer control how that's instantiated. Should you desire either of these, beans are suitable; if you don't, then new it up.
In you simple case, it does not seem to be necessary to add DateToLocalDateTimeConverter as a spring bean.
Reasons to add DateToLocalDateTimeConverter as a spring bean:
If it would make the implementation of conversionService() more readable (not the case in the question example)
You need the DateToLocalDateTimeConverter in other beans
The implementation of DateToLocalDateTimeConverter itself would need to have Spring beans injected, i.e. using #Autowired

How to inject dependencies in entities with Spring-Data and Hibernate [duplicate]

Is it possible to inject beans to a JPA #Entity using Spring's dependency injection?
I attempted to #Autowire ServletContext but, while the server did start successfully, I received a NullPointerException when trying to access the bean property.
#Autowired
#Transient
ServletContext servletContext;
You can inject dependencies into objects not managed by the Spring container using #Configurable as explained here: http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/aop.html#aop-atconfigurable.
As you've realized by now, unless using the #Configurable and appropriate AspectJ weaving configuration, Spring does not inject dependencies into objects created using the new operator. In fact, it doesn't inject dependencies into objects unless you've retrieved them from the ApplicationContext, for the simple reason that it simply doesn't know about their existence. Even if you annotate your entity with #Component, instantiation of that entity will still be performed by a new operation, either by you or a framework such as Hibernate. Remember, annotations are just metadata: if no one interprets that metadata, it does not add any behaviour or have any impact on a running program.
All that being said, I strongly advise against injecting a ServletContext into an entity. Entities are part of your domain model and should be decoupled from any delivery mechanism, such as a Servlet-based web delivery layer. How will you use that entity when it's accessed by a command-line client or something else not involving a ServletContext? You should extract the necessary data from that ServletContext and pass it through traditional method arguments to your entity. You will achieve a much better design through this approach.
Yes, of course you can. You just need to make sure the entity is also registered as a Spring managed bean either declaratively using <bean> tags (in some spring-context.xml) or through annotations as shown below.
Using annotations, you can either mark your entities with #Component (or a more specific stereotype #Repository which enables automatic exception translation for DAOs and may or may not interfere with JPA).
#Entity
#Component
public class MyJAPEntity {
#Autowired
#Transient
ServletContext servletContext;
...
}
Once you've done that for your entities you need to configure their package (or some ancestor package) for being scanned by Spring so that the entities get picked up as beans and their dependencies get auto wired.
<beans ... xmlns:context="..." >
...
<context:component-scan base-package="pkg.of.your.jpa.entities" />
<beans>
EDIT : (what finally worked and why)
Making the ServletContext static. (remove #Autowired)
#Transient
private static ServletContext servletContext;
Since, JPA is creating a separate entity instance i.e. not using the Spring managed bean, it's required for the context to be shared.
Adding a #PostConstruct init() method.
#PostConstruct
public void init() {
log.info("Initializing ServletContext as [" +
MyJPAEntity.servletContext + "]");
}
This fires init() once the Entity has been instantiated and by referencing ServletContext inside, it forces the injection on the static property if not injected already.
Moving #Autowired to an instance method but setting the static field inside.
#Autowired
public void setServletContext(ServletContext servletContext) {
MyJPAEntity.servletContext = servletContext;
}
Quoting my last comment below to answer why do we have to employ these shenanigans:
There's no pretty way of doing what you want since JPA doesn't use the Spring container to instantiate its entities. Think of JPA as a separate ORM container that instantiates and manages the lifecycle of entities (completely separate from Spring) and does DI based on entity relationships only.
After a long time I stumbled across this SO answer that made me think of an elegant solution:
Add to your entities all the #Transient #Autowired fields you need
Make a #Repository DAO with this autowired field:
#Autowired private AutowireCapableBeanFactory autowirer;
From your DAO, after fetching the entity from DB, call this autowiring code:
String beanName = fetchedEntity.getClass().getSimpleName();
autowirer.autowireBean(fetchedEntity);
fetchedEntity = (FetchedEntity) autowirer.initializeBean(fetchedEntity, beanName);
Your entity will then be able to access the autowired fields as any #Component can.

#Inject only working for POJOs created by CDI container?

I just want to confirm that I fully understood the prerequisites for CDI to work. If I have a class A:
public class A {
#Inject private B b;
}
Now when I instantiate this class using:
A a = new A();
In that case, A.b will be null.
But if I define in another class a member:
#Inject A a;
and later use a, a.b will be correctly populated?
Does CDI only work if the class requiring an injection was also created by CDI container? Or what am I missing if injections turn out to be null while creating a POJO using ordinary instantiation with new (yes, I got beans.xml in place)?
Does CDI only work if the class requiring an injection was also
created by CDI container?
Yes, that's pretty much it. The lifecycle of a ManagedBean is controlled by the container and should never be instantiated with the new keyword (BTW: the same is true for EJBs & Spring beans). If you need to create a new ManagedBean you will probably want to use a producer method.
While others have stated correctly that for the most part DI containers will not inject dependencies into bean that they did not instantiate this is not entirely true.
Spring has a wonderful feature that will autowire the bean when you create it using new A().
You just have to use AspectJ and mark your bean with the #Configurable annotation.
#Configurable
public class A {
#Inject private B b;
}
Its actually kind of an awesome feature cause you can do Active Record style POJO's while still honoring your DI (its in fact how Spring Roo does it).
You should also know that with Spring you can autowire a bean programmatically after its been instantiated with the AutowireCapableBeanFactory. This is how it typically autowires JUnit Test Case Classes because JUnit creates the test case classes.
Yes Spring is not CDI but in theory you could write your own #Configurable for CDI or there is probably a CDI way of doing the above.
That being said the above is sort of a sophisticated feature (and kind of a hack) and as #JanGroth mentioned understaning the lifecycle bean management of the container is critical whether its CDI, Spring, Guice etc.
You may use BeanProvider.injectFields(myObject); from Apache DeltaSpike.
Yes, #Inject works only inside a container because it is done using interceptors on method calls. When the container creates a bean it wrappes it in interceptors which perform injection, and in the case of instantiation using new no interceptors will be called during bean method invocation, and there will be no injection.
Here's the conditions needed for a class to be a managed bean (and hence, for the #Inject annotation to work on its fields/methods):
http://docs.oracle.com/javaee/6/tutorial/doc/gjfzi.html

Categories

Resources