Spring #Bean configs and java polymorphism - java

I've been making increasingly heavy use of the new #Bean configuration style in Spring 3, as a more type-safe alternative to XML bean definition files. Occasionally, though, this type-safety can prevent you do what should be valid things, due to a combination of Java's lack of type expressiveness, and Spring scoped proxies.
A full unit test which demonstrates the problem is below, but briefly put I have a class ServiceBean, which implements interfaces ServiceA and ServiceB. This bean is a scoped proxy (session-scoped in this case). I also have beans ClientA and ClientB, which are injected with objects of type ServiceA and ServiceB respectively.
In Spring XML config, there's no problem with this. Spring generates a JDK-proxy for the ServiceBean, which implements both interfaces, and both are injected into the client beans. It's all reflective, and the types are fine at runtime.
Try this in #Bean-style, though, and you have problems. Here's the demonstrative test.
Firstly, the services:
public interface ServiceA {}
public interface ServiceB {}
public class ServiceBean implements ServiceA, ServiceB {}
Now, the clients:
public class ClientA {
public ClientA(ServiceA service) {}
}
public class ClientB {
public ClientB(ServiceB service) {}
}
Now, the Spring bean definitions:
#Configuration
public class ScopedProxyConfig {
#Bean #Scope(value=WebApplicationContext.SCOPE_SESSION, proxyMode=ScopedProxyMode.INTERFACES)
public ServiceBean services() {
return new ServiceBean();
}
#Bean
public ClientA clientA() {
return new ClientA(services());
}
#Bean
public ClientB clientB() {
return new ClientB(services());
}
}
And finally, the unit test and support context:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class ScopedProxyTest {
private #Resource ClientA clientA;
private #Resource ClientB clientB;
public #Test void test() {
assertThat(clientA, is(notNullValue()));
assertThat(clientB, is(notNullValue()));
}
}
<beans>
<context:annotation-config/>
<bean class="test.ScopedProxyConfig"/>
</beans>
(XML namespaces omitted for clarity).
This all compiles nicely. Run the test, though, and you get a type casting runtime exception:
Caused by: java.lang.ClassCastException: $Proxy11 cannot be cast to test.ServiceBean
at test.ScopedProxyConfig$$EnhancerByCGLIB$$d293ecc3.services()
at test.ScopedProxyConfig.clientA(ScopedProxyConfig.java:26)
It's not clear to me exactly what this is telling me, but it appears to be a clash between the JDK proxy (which implements ServiceA and ServiceB) and the ServiceBean object.
I've tried getting clever with generics:
#Bean #Scope(value=WebApplicationContext.SCOPE_SESSION, proxyMode=ScopedProxyMode.INTERFACES)
public <T extends ServiceA & ServiceB> T services() {
return (T)new ServiceBean();
}
But that doesn't even compile.
This isn't an especially exotic situation, I think, and I've run into it a few times before. In the past, the workaround has been to use TARGET_CLASS proxying instead of interface proxying, but that's not an option for me here.
Can anyone figure out how to make this work?

I think you'll have to go for a more interface-based solution:
create an interface ServiceC:
public interface ServiceC extends ServiceA, ServiceB {}
and let ServiceBean implement that interface
public class ServiceBean implements ServiceC{}
And in your ScopedProxyConfig:
#Bean #Scope(value=WebApplicationContext.SCOPE_SESSION,
proxyMode=ScopedProxyMode.INTERFACES)
public ServiceC services() {
return new ServiceBean();
}
Consistent use of interfaces should let Spring work with JDK proxies.

This one at least compiles, perhaps it will work:
#Bean #Scope(value=WebApplicationContext.SCOPE_SESSION, proxyMode=ScopedProxyMode.INTERFACES)
public <T extends ServiceA & ServiceB> T services() {
return (T)new ServiceBean();
}
#Bean
public ClientA clientA() {
return new ClientA(this.<ServiceBean>services());
}
#Bean
public ClientB clientB() {
return new ClientB(this.<ServiceBean>services());
}

Related

Spring bean decoration without ambiguity errors

I have the following scenario: A factory interface with 2 implementations, while the second one used as decorator to the first one.
public final class BaseMailFactory implements MailFactory {
#Autowired
private final ClassA classA;
#Autowired
private final ClassB classB;
public Mail createMail(){
.
.
.
}
}
public final class MetricAwareMailFactory implements MailFactory {
private final MailFactory mailFactory;
public Mail createMail(){
var mail = mailFactory.createMail();
return new MetricsAwareMail(mail);
}
}
#Configuration
public class MailFactoryConfiguration {
#Bean
public MailFactory metricsAwareMailFactory(){
return new MetricAwareMailFactory(???);
}
}
The wrapped object previously instantiated through spring container (context), hence all auto wired fields populated successfully. After creation of the second implementation I am struggle to find an elegant way to initialize the first instance without adding multiple implementations to MailFactory interface which leads to application startup errors due to ambiguity.
I know that I can use qualifies for that but they pollute my code.
I am looking for a way to instantiate a class through spring but without actually register it as a bean, in older spring versions I get to use anonymous beans for such purposes.
I found the #Primary annotation useful here:
#Configuration
public class MailFactoryConfiguration {
#Bean
#Lazy
MailFactory baseMailFactory(){
return new BaseMailFactory();
}
#Bean
#Primary
public MailFactory metricsAwareMailFactory(){
return new MetricAwareMailFactory(baseMailFactory());
}
}
I such way, both beans will be created but the primary one will be selected in case of multiple implementations.

Spring boot inject bean at runtime based on request endpoint/request param

I have an interface that has two implementations, and I'd like to conditionally inject either of the two implementations in a spring boot service.
The point is that the eligible implementation should be picked up based on the request message (JSON mapped to a POJO).
My searches leaded me to implement a FactoryBean to control selecting between those two implementations, and to keep the factory telling spring that the beans are not singleton (by returning false for the isSingleton method).
But if this is the right way, I am still not sure how to get the request message to check it and return the right bean.
Can you please tell me if I am on the right track for what I am trying to attain?
=============
UPDATE
I do not want to pollute my code and deal with managing the relation between my service and the dependencies' implementation in the service.
Considering that I will need to deal with more implementations in the future, I need my service to care only about its responsibility.
I need my service to have only one reference of the generic interface and deal with it in an abstracted way.
I need to find a spring-based way to choose the right implementation for each request based on a condition that is derived from the request itself, and inject it in the service.
One option is to inject both beans and conditionally pick the required bean. You can autowire classes implementing same interface into a Map.
Following example uses a factory class to hide the conditional check.
#Component("type1")
public class Type1 implements SomeInterface{}
#Component("type2")
public class Type2 implements SomeInterface{}
#Component
public class MyTypeFactory {
#Autowired
private Map<String, SomeInterface> typesMap;
public SomeInterface getInstance(String condition){
return typesMap.get(condition);
}
}
#Component
public class MyService {
#Autowired
private MyTypeFactory factory;
public void method(String input){
factory.getInstance(input).callRequiredMethod();
}
}
You could #Autowire both beans in the controller and decided based on the request which one to return.
Consider the below interface:
public interface MyInterface { ... }
Sample config:
#Configuration
public class MyConfig {
#Bean("first")
public MyInterface firstBean() { ... }
#Bean("second")
public MyInterface secondBean() { ... }
}
Sample controller:
#RestController
public class MyController {
#Autowire
#Qualifier("first")
public MyInterface first;
#Autowire
#Qualifier("second")
public MyInterface second;
#GetMapping
public MyInterface doStuff(#RequestBody body) {
if(shouldReturnFirst(body)){
return first;
} else {
return second;
}
}
}
Note that you should most likely not do it this way though, but have a single service, say MyService that should implement this logic for you.
#Component
public class MyService {
public MyInterface doStuff(body) {
if(shouldReturnFirst(body)){
// build your response here
} else {
// build your response here
}
}
}
And just delegate to the service from the controller
#GetMapping
public MyInterface doStuff(#RequestBody body) {
return myService.doStuff(body);
}
Spring has a concept of Conditional Bean...
Have a look here https://www.intertech.com/Blog/spring-4-conditional-bean-configuration/

Parameter 0 of constructor in ..... Spring Boot

I have a problem when launch my app. Could somebody help me to solve this issue?
Parameter 0 of constructor in com.journaldev.elasticsearch.service.BookServiceImpl required a bean of type 'com.journaldev.elasticsearch.dao.search.BookRepositorySearch' that could not be found.
Action:
Consider defining a bean of type 'com.journaldev.elasticsearch.dao.search.BookRepositorySearch' in your configuration.
GenericRepository
public interface GenericRepository<T, K> {
Map<String, Object> get(final K id);
}
GenericRepositoryImpl
public class GenericRepositoryImpl<T, K extends Serializable> implements GenericRepository<T, K> {
private RestHighLevelClient restHighLevelClient;
private ObjectMapper objectMapper;
public GenericRepositoryImpl(ObjectMapper objectMapper, RestHighLevelClient restHighLevelClient) {
this.objectMapper = objectMapper;
this.restHighLevelClient = restHighLevelClient;
}
#Override
public Map<String, Object> get(K id) {
return null;
}
}
BookRepositorySearch
#Component
public interface BookRepositorySearch extends GenericRepository<Book, Long> {}
BookService
public interface BookService {
Map<String, Object> get(final Long id);
}
BookServiceImpl
#Service
public class BookServiceImpl implements BookService {
private final BookRepositorySearch bookRepositorySearch;
public BookServiceImpl(BookRepositorySearch bookRepositorySearch) {
this.bookRepositorySearch = bookRepositorySearch;
}
#Override
public Map<String, Object> get(Long id) {
return null;
}
}
From your previous comments, looks like you want to keep BookRepositorySearch as an interface. If that's the case, you need to create a concrete instance of that interface and put #Component on that.
You don't need #Component on your interface declaration and you can't extend a class in an interface.
public interface BookRepositorySearch {}
Create a concrete type that implements the interface and extends extends GenericRepository<Book, Long> you want to autowire and put #Component on it:
#Component
public class BookRepositorySearchImpl
implements BookRepositorySearch
extends GenericRepository<Book, Long>
{}
https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-factory-class-ctor
Instantiation with a constructor
When you create a bean by the
constructor approach, all normal classes are usable by and compatible
with Spring. That is, the class being developed does not need to
implement any specific interfaces or to be coded in a specific
fashion. Simply specifying the bean class should suffice. However,
depending on what type of IoC you use for that specific bean, you may
need a default (empty) constructor.
The Spring IoC container can manage virtually any class you want it to
manage; it is not limited to managing true JavaBeans. Most Spring
users prefer actual JavaBeans with only a default (no-argument)
constructor and appropriate setters and getters modeled after the
properties in the container. You can also have more exotic
non-bean-style classes in your container. If, for example, you need to
use a legacy connection pool that absolutely does not adhere to the
JavaBean specification, Spring can manage it as well.
I solved it with this configuration.
Look for #EnableAutoConfiguration in your Configuration file.
#Configuration
#EnableJpaRepositories(basePackages = "com.akog02.repostories")
#EntityScan(basePackages = "com.akog02.domain")
#EnableTransactionManagement
#EnableAutoConfiguration
public class WebConfiguration {
}
First of, You need to "tell" spring what to pass as a parameter. The simplest option is the one mentioned by #Berger in a comment. If for some reason that is not a good approach for you (eg. BookRepositorySearch is not a spring managed bean), you can make a java config file with some more logic:
#Configuration
public class Config {
// you can use #Autowired here
#Bean
public BookService bookService() {
return new BookServiceImpl(--pass your parameter here, get it however you want--)
}
}
edit:
Apparently Spring doesn't require #Autowired anymore (thanks #Mark Rotteveel).
So the problem is that spring doesn't have an instance of your class. The reason for that is (I think) that you use a class parameter instead of an interface. If You just create a marker interface that BookRepositorySearch implements and use that as an argument instead of the actual inplementation, I would expect it to work.
Another solution is what I wrote above already, but for the BookRepositorySearch class.
#Configuration
public class Config {
// you can use #Autowired here
#Bean
public BookRepositorySearch bookRepositorySearch () {
return new BookRepositorySearch();
}
}
This way Spring will have it's beloved instance ;)
How do you inherit a class as an interface?
#Component
public interface BookRepositorySearch extends GenericRepository<Book, Long> {}
Change this interface with a class then try again.
#Component
public class BookRepositorySearch extends GenericRepository<Book, Long> {}
You must add #EnableJpaRepositories("org.tennis.Tennnis.dao") in Prin

#Autowired attribute that needs a parameter to be instantiated

I'm new to spring boot, and I need to know how to use #autowired in an attribute that needs parameters to be instantiated.
Please bear in mind the following illustrative situation. It would be something like this:
public class MyClassA{
public SpecificClass myMethod(){
//some logic
}
}
public class MyClassB extends MyClassA{
#Autowired
MyComponent myComponent (myMethod()); //here is my doubt, because my component needs a parameter to be built
}
#Component
public class MyComponent{
public MyComponent(SpecificClass foo){
this.foo=foo;
}
That's not really proper design if your intention is to work with dependency injection. There shouldn't be a direct dependency to the superclass' method like that. Injecting the dependencies indirectly as you're supposed to do would result in something like the following
public class MyClassB extends MyClassA {
#Autowired
private MyComponent myComponent;
}
#Configuration
public class SomeConfig {
#Bean
#Autowired
public MyComponent createComponent(SpecificClass foo) {
// SpecificClass is also injected, providing another layer of indirection
return new MyComponent(foo);
}
}
#Autowired only tells Spring to inject a component into a constructor, field, or method parameter. The injected component is instantiated by the bean container before that. I assume what you are looking for is a way to create MyComponent in such a way that it also receives a Spring Bean.
In your example you could achieve this with the following
#Configuration
public class MyClassA{
#Bean //the bean would have the name 'myMethod', so maybe change that
public SpecificClass myMethod(){
//some logic
}
}
//this needs to be a component, service, ...
#Component
public class MyClassB {
#Autowired
MyComponent myComponent;
}
#Component
public class MyComponent{
#Autowired //Spring wires the Bean 'myMethod' in here, autowired is not needed in the latest Spring Versions
public MyComponent(SpecificClass foo){
this.foo=foo;
}
}
This is a basic Spring question, and not specific to Spring Boot. To better understand wiring you can take a look at the Spring 4 Framework Reference Documentation.

Spring 3.2 Autowire generic types

So I have a number of generics in Spring 3.2 and ideally my architecture would look something like this.
class GenericDao<T>{}
class GenericService<T, T_DAO extends GenericDao<T>>
{
// FAILS
#Autowired
T_DAO;
}
#Component
class Foo{}
#Repository
class FooDao extends GenericDao<Foo>{}
#Service
FooService extends GenericService<Foo, FooDao>{}
Unfortunately with multiple implementations of the generics the autowiring throws an error about multiple matching bean definitions. I assume this is because #Autowired processes before type erasure. Every solution I've found or come up with looks ugly to me or just inexplicably refuses to work. What is the best way around this problem?
How about adding a constructor to the GenericService and move the autowiring to the extending class, e.g.
class GenericService<T, T_DAO extends GenericDao<T>> {
private final T_DAO tDao;
GenericService(T_DAO tDao) {
this.tDao = tDao;
}
}
#Service
FooService extends GenericService<Foo, FooDao> {
#Autowired
FooService(FooDao fooDao) {
super(fooDao);
}
}
Update:
As of Spring 4.0 RC1, it is possible to autowire based on generic type, which means that you can write a generic service like
class GenericService<T, T_DAO extends GenericDao<T>> {
#Autowired
private T_DAO tDao;
}
and create multiple different Spring beans of it like:
#Service
class FooService extends GenericService<Foo, FooDao> {
}
Here is a closest solution. The specialized DAOs are annotated at the business layer. As in the question from OP, the best effort would be having an annotated DAO in the EntityDAO generic template itself. Type erasure seems to be not allowing the specialized type information to get passed onto the spring factories [resulting in reporting matching beans from all the specialized DAOs]
The Generic Entity DAO template
public class EntityDAO<T>
{
#Autowired
SessionFactory factory;
public Session getCurrentSession()
{
return factory.getCurrentSession();
}
public void create(T record)
{
getCurrentSession().save(record);
}
public void update(T record)
{
getCurrentSession().update(record);
}
public void delete(T record)
{
getCurrentSession().delete(record);
}
public void persist(T record)
{
getCurrentSession().saveOrUpdate(record);
}
public T get(Class<T> clazz, Integer id)
{
return (T) getCurrentSession().get(clazz, id);
}
}
The Generic Entity Based Business Layer Template
public abstract class EntityBusinessService<T>
implements Serializable
{
public abstract EntityDAO<T> getDAO();
//Rest of code.
}
An Example Specialized Entity DAO
#Transactional
#Repository
public class UserDAO
extends EntityDAO<User>
{
}
An Example Specialized Entity Business Class
#Transactional
#Service
#Scope("prototype")
public class UserBusinessService
extends EntityBusinessService<User>
{
#Autowired
UserDAO dao;
#Override
public EntityDAO<User> getDAO()
{
return dao;
}
//Rest of code
}
You can remove the #autowire annotation and perform delayed “autowire” using #PostConstruct and ServiceLocatorFactoryBean.
Your GenericService will look similar to this
public class GenericService<T, T_DAO extends GenericDao<T>>{
#Autowired
private DaoLocator daoLocatorFactoryBean;
//No need to autowried, autowireDao() will do this for you
T_DAO dao;
#SuppressWarnings("unchecked")
#PostConstruct
protected void autowireDao(){
//Read the actual class at run time
final Type type;
type = ((ParameterizedType) getClass().getGenericSuperclass())
.getActualTypeArguments()[1];
//figure out the class of the fully qualified class name
//this way you can know the bean name to look for
final String typeClass = type.toString();
String daoName = typeClass.substring(typeClass.lastIndexOf('.')+1
,typeClass.length());
daoName = Character.toLowerCase(daoName.charAt(0)) + daoName.substring(1);
this.dao = (T_DAO) daoLocatorFactoryBean.lookup(daoName);
}
daoLocatorFactoryBean does the magic for you.
In order to use it you need to add an interface similar to the one below:
public interface DaoLocator {
public GenericDao<?> lookup(String serviceName);
}
You need to add the following snippet to your applicationContext.xml
<bean id="daoLocatorFactoryBean"
class="org.springframework.beans.factory.config.ServiceLocatorFactoryBean">
<property name="serviceLocatorInterface"
value="org.haim.springframwork.stackoverflow.DaoLocator" />
</bean>
This is a nice trick and it will save you little boilerplate classes.
B.T.W I do not see this boilerplate code as a big issue and the project I working for uses matsev approach.
Why do you want a generic service ? Service classes are meant for specific units of work involving multple entities. You can just inject a repository straight into a controller.
Here is an example of generic repository with constructor argument, you could also make each method Generic instead and have no constructor argument. But each method call would require class as parameter:
public class DomainRepository<T> {
#Resource(name = "sessionFactory")
protected SessionFactory sessionFactory;
public DomainRepository(Class genericType) {
this.genericType = genericType;
}
#Transactional(readOnly = true)
public T get(final long id) {
return (T) sessionFactory.getCurrentSession().get(genericType, id);
}
Example of bean definition for the generic repository - you could have multple different beans, using different contstructor args.
<bean id="tagRepository" class="com.yourcompnay.data.DomainRepository">
<constructor-arg value="com.yourcompnay.domain.Tag"/>
</bean>
Depdncy injection of bean using resource annotation
#Resource(name = "tagRepository")
private DomainRepository<Tag> tagRepository;
And this allows the Domainreposiroty to be subclassed for specific entities/methods, which woul dallow autowiring :
public class PersonRepository extends DomainRepository<Person> {
public PersonRepository(){
super(Person.class);
}
...
You should use autowiring in classes which extends these generics
For this question one needs to understand about what autowire is. In common terms we can say that through autowire we create a object instance/bean at the time of deployment of the web app. So now going with the question if you are declaring autowiring in multiple places with the same name. Then this error comes. Autowiring can be done in multiple ways so if you are using multiple type of autowiring technique, then also one could get this error.
Complete Generic Solution using Spring 4:
Domain Class
#Component
class Foo{
}
#Component
class Bar{
}
DAO Layer
interface GenericDao<T>{
//list of methods
}
class GenericDaoImpl<T> implements GenericDao<T>{
#Autowired
SessionFactory factory;
private Class<T> domainClass; // Get Class Type of <T>
public Session getCurrentSession(){
return factory.getCurrentSession();
}
public DaoImpl() {
this.domainClass = (Class<T>) GenericTypeResolver.resolveTypeArgument(getClass(), DaoImpl.class);
}
//implementation of methods
}
interface FooDao extends GenericDao<Foo>{
//Define extra methods if required
}
interface BarDao extends GenericDao<Bar>{
//Define extra methods if required
}
#Repository
class FooDao extends GenericDaoImpl<Foo> implements FooDao{
//implementation of extra methods
}
#Repository
class BarDao extends GenericDaoImpl<Bar> implements BarDao{
//implementation of extra methods
}
Service Layer
interface GenericService<T>{
//List of methods
}
class GenericServiceImpl<T> implements GenericService<T>{
#Autowire
protected GenericDao<T> dao; //used to access DAO layer
}
class FooService extends GenericService<Foo>{
//Add extra methods of required
}
class BarService extends GenericService<Bar>{
//Add extra methods of required
}
#Service
class FooServiceImpl extends GenericServiceImpl<Foo> implements GenericService<Foo>{
//implementation of extra methods
}
#Service
class BarServiceImpl extends GenericServiceImpl<Bar> implements GenericService<Bar>{
//implementation of extra methods
}

Categories

Resources