Instantiating bean using factory pattern in Spring MVC 3 - java

I got Object coming in a REST web service controller's web method which is locally initialized.
#RequestMapping(method = RequestMethod.POST,value = "/test",headers="Accept=*/*")
public #ResponseBody ModelAndView computeDetails(#RequestBody RequestObj reqObj, ModelMap model) {
System.out.println(reqObj.getcode());
return new ModelAndView("responsedetails", "object", reqObj);
}
This RequestObj object holds the key code to instantiate dependency using factory.
Different codes classes have been defined which implement BaseCode Interface.
How can I use factory method to instantiate particular code class based on code value coming in as BaseCode type in my service bean?
Any idea? Thanks in advance.

What I usually do in such cases is:
inject the factory into the controller using Spring's bean
create a method getBaseCode(String code) in the factory (please note: String here stands for code type, so use the actual code type if not String
make getBaseCode returning the BaseCode interface while constructing the real implementation
supposing you have an execute method in BaseCode, use the getBaseCode method into the controller to get the real collaborator and then call the execute method to perform the actual action
Ignoring the first point (which I think you can easily looking at any Spring tutorial) the factory will be something like
public class BaseCodeFactory {
public BaseCode getBaseCode(String code) {
if(code.equals("something")) return new ThisBaseCodeImpl();
else //and so on
}
}
while computeDetails becomes similar to:
#RequestMapping(method = RequestMethod.POST,value = "/test",headers="Accept=*/*")
public #ResponseBody ModelAndView computeDetails(#RequestBody RequestObj reqObj, ModelMap model) {
//...
factory.getBaseCode(reqObj.getcode()).execute();
//...
}
As a side note, I will not go for names like the one I choose here, I suggest you to look for something more significative in your domain (BaseCode has no meaning for example), take this snippets just as a directive.
Base on OP comment. If you have ThisBaseCodeImpl which makes use of other Spring bean you can
annotate it with #Configurable so, when you use new ThisBaseCodeImpl(/*args if you like*/) its bean are instantiated by Spring. I don't personally like this solution since, in my opinion, it pollutes the code with hidden Spring's bean. On the other hand is quite flexible, since it allows you to manage both runtime constructor arguments and Spring beans
add ThisBaseCodeImpl to the Spring context and change the factory, so that a collaborator for ThisBaseCodeImpl is injected into it.
1st point example:
#Configurable
public class ThisBaseCodeImpl {
#Resource
private Bean bean;
}
2nd point example:
public class BaseCodeFactory {
#Resource
ThisBaseCodeImpl thisBaseCodeImpl;
public BaseCode getBaseCode(String code) {
if(code.equals("something")) return thisBaseCodeImpl;
else //and so on
}
}

I'm not sure if I understood your problem well, but in general spring dependencies have nothing to do here. Just write custom Factory class and return BaseCode implemetation depending on the reqObj.getcode().

I did it this way -
Make your factory as ServletContextAware in a way to get the currentContext. And define getInstance method as
WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
ctx.getBean(classNameToBeInstantiated);
Define your bean's inheritance in spring context so that Spring injects its dependencies.

Related

Create bean only if property file/xml file exists [duplicate]

Lets say i have two beans:
class MyBean implements BeanInterface(){}
class MyBean2 implements BeanInterface(){}
And if specific property exists, i want to create MyBean, otherwise I want to create MyBean2(). How can i do this?
#Bean
#ConditionalOnProperty(name = "property.validation")
public BeanInterface beanInterface() {
return new MyBean();
}
works if I want to create MyBean if property exists, but how do I create MyBean2 if it doesn't?
#Bean
#ConditionalOnMissingBean(MyBean.class)
public BeanInterface beanInterface() {
return new MyBean2();
}
complains that method with same name exists, and if i understand it correctly, the methods name need to be camelCase name of the bean.
How do i do this?
Thanks
//edit i tried:
#Bean
#ConditionalOnProperty(name = "property.validation")
#Order(1)
public BeanInterface beanInterface() {
return new MyBean();
}
#Bean("beanInterface")
#ConditionalOnMissingBean(MyBean.class)
#Order(2)
public BeanInterface beanInterface() {
return new MyBean2();
}
but it didnt work, second bean is not getting created when property is missing.
You can specify bean name #Bean("beanInterface") then method name can be anything.
You have Java configuration at your hands, so use that to your advantage. Not everything needs annotations to be fixed.
#Bean
public BeanInterface myBean(Environment env) {
String validation = env.getProperty("property.validation", String.class);
return validation != null ? new MyBean(validation) : new MyBean2();
}
The name of the method doesn't matter it can be anything you like.
Spring and Spring boot provide a a following solution: If you need to choose one implementation of the interface at runtime, than you inject all implementations and choose appropriate one at runtime. Assuming that you have an interface DataSource with multiple implementations here is how you inject them all:
#Autowired
private List<DataSource> dataSources;
You can read about this solution here.
This is a standard solution, but I really don't like it as it is waistful to inject all implementations. So, I wrote a feature that is available as part of MgntUtils open-source library. That feature allows you to create a static factory per each interface, and once you add any implementation of that interface declared as a Bean, that implementation will be added automatically at start up into a relevant factory. So, instead of injecting all implementations in your class you at runtime take from the factory needed implementation. I think it is much more elegant solution, and it has been battle-tested and it works well. Here is Javadoc that explains the concept and has a detailed example on how to use it: Lifecycle management. Also here is the article that describes this feature in detail: Non-intrusive access to "Orphaned" Beans in Spring framework. The library is available as Maven artifact at Maven central ad also on Github including javadoc and source code. In the source code there is a working example on how to use this feature

How to invoke a method in a service class with #transactional and #service annotation by reflection?

First, forgive my poor English, I am just working hard on my English:).
I'm trying to find an easy way to set the communication more simple between front-end and back-end, because I use ActiveMQ as the Message Oriented Middleware. So XML string became the request carrier.
For example, front-end send a string request to back-end including package name, class name, method name and parameters list, in this way, back-end is allowed to invoke the correct method by these information, and send invoke result back to front-end. It works, but not perfect. The problem is that when I tried to invoke a method in a service class with #Transational and #Service annotation(which is the common practice to connect to the database),the transaction seemed not being opened, request and response are both received, just left a lot of sleeping connection in mysql database process, as much as the ActiveMQ's consumers every time.
Target method in service class:
#Service
#Transactional
public class UserService {
#Autowired
private IUserDAO udao;
public User getUserByName(String username) {
return udao.findByUsername(username);
}
}
Invoke method(some code has been omitted):
#Component
public class ReflectTool {
public Object invokeMethod(String packageName,String className,String methodName,List paramList) {
BeanFactory beanFactory = new ClassPathXmlApplicationContext("applicationContext.xml");
Object obj = beanFactory.getBean(packageName+"."+className);
Class cla = obj.getClass();
Method method = findMethod(Class cla,String methodName);
return method.invoke(obj, params);
}
}
I've searched a lot answer, but none of them worked. Like:use a proxy object to invoke but not the target object, cause spring framework has used a proxy class instead the service class with #Transactional annotation to help we manager the transaction, but the code (AopUtils.isAopProxy(obj)) returns true, so it mean the object is exactly a proxy object which I got from the spring context? I'm not very familiar with Dynamic Agent Model.
Thanks for your attention, please tell me if I did something wrong.
Well I was going to this I'd try the following approach:
DON'T use BeanFactory, inject in your ReflectTool the ApplicationContect: #Autowired private ApplicationContext applicationContext; if the beans you want to recover implements some interface or extends a class then maybe you can replace this injection by a Map. Spring will make it work
Try to get the object of the bean you need.
the lines you have regarding the capture of the method and execution should work since it is an bean calling another bean.
Hope this helps. I had a similar situation where I needed to invoke a #Transactional method and I fixed in a similar way I have described.

Can spring execute a factory bean on #RequestBody

If I have a Spring webapp, with an endpoint like so:
#Autowired
UnpublishedStuffFactory unpublishedStuffFactory;
#RequestMapping(value = "/{id}", method = RequestMethod.PUT)
#ResponseBody
public OutputStuff update(#RequestBody Stuff stuff, #PathVariable String id) {
UnpublishedStuff uStuff = unpublishedStuffFactory.get(stuff);
//handle the request
}
UnpublishedStuffFactory.java:
#Component
public class UnpublishedStuffFactory {
#Autowired
//some autowired beans
public UnpublishedStuff get(Stuff stuff) {
return new UnpublishedStuff(stuff, /*some autowired beans*/);
}
}
So Stuff is my domain object (simple POJO). OutputStuff is something I generate (some metadata etc) and return if update was ok.
It all works fine, however I would like spring to automatically execute this factory method when request comes in, and inject UnpublishedStuff to the update method, instead of injecting Stuff.
Basically UnpublishedStuff is kind of a decorator around Stuff that adds functionality via other autowired beans (from the factory) to validate, publish etc to Stuff (I do not want this functionality in Stuff, I want it to stay a basic POJO, hence the decorator).
Is there a way to do this? Or maybe there is a better approach to this stuff?
Thanks for help :)

spring autowiring with processInjectionBasedOnCurrentContext(this);

I have following situation. There is POJO which has autowired implementation of an interface, using some spring magic as shown bellow. However this dependency doesn't get resolved if creation of channels is managed via spring bean. It only works if POJO factory creates channels. Example bellow.
#Controller
public class Test{
#RequestMapping(value = "/load", method = RequestMethod.GET)
public #ResponseBody String testConfiguration() {
// this is pojo and here it works, channels within have wired interface implementation
StaticFactory.getChannels(null);
// if i call same method within spring managed bean (#Service)
// then it doesnt work
System.out.println("channels created");
return "alive";
}
}
Created Channels are POJO but they have autowired interface implementation, which should be enabled with the following in constructor:
public DummyChannel() {
// enables dependency injection of spring managed beans into POJO
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
}
public class StaticFactory {
public static List<SmppChannel> getChannels(Map<ChannelMode, Integer> channelsDefinition) {
List<SmppChannel> dummyChannels = new ArrayList<>();
DummyChannel d = new DummyChannel();
System.out.println("here");
dummyChannels.add(new DummyChannel());
return dummyChannels;
}
}
Now, this thing works if i have non-spring managed Factory. Regardless if mentioned factory is static or not when it creates channels, they have properly wired interface implementation.
However, if i copy paste exactly same code form the factory into Spring managed Bean annotated with #Service, wired dependency is null in created channel.
Could somebody tell me what am i missing here, why things get injected when the factory of channels is not managed by the Spring ?
Edit Solution: // Okay, so the problem is in the fact that DummyChannels enable autowiring support in constructor while Spring beans are still not loaded. It is working if i do this within method that should access autowired service rather then the constructor of DummyChannel.
Have you enabled annotation-config and component-scan in your xml or java configuration? Is the class that you want to inject annotated with #Service or #Resource?
Are you building a Web Service with JAX-WS? If yes, then I think your class (the one doing the autowiring) must implement SpringBeanAutowiringSupport so that Spring's IoC container can handle the injection.

#Inject not injecting and causing NullPointerException using component scanning

My application context XML is simple:
<context:component-scan base-package="com.depressio.spring" />
In that package, I have my configuration:
package com.depressio.spring
#Configuration
#ComponentScan(basePackages = "com.depressio")
public class DepressioConfiguration
{
#Inject private ApplicationContext context;
}
Within com.depressio, there's a repository (DAO):
package com.depressio.dao;
#Repository
public class ParameterDAO
{
public Parameter getParameter(long ID) { ... }
}
... and a service where injection is working just fine (no NPE when parameterDAO is used):
package com.depressio.resource;
#Service
#Path("/depressio/parameters")
public class ParameterResource
{
#Inject private ParameterDAO parameterDAO;
#Path("{id}")
public Response getParameter(long parameterID)
{
return Response.ok(parameterDAO.getParameter(parameterID).legacyFormat()).build();
}
}
However, the legacyFormat() method call there constructs another object. Within that object, I have to inject a different DAO (also annotated with #Repository, though). That injection isn't working.
So, we have the original Parameter object:
package com.depressio.domain;
public class Parameter
{
...
public LegacyParameter legacyFormat()
{
return new LegacyParameter(this);
}
}
... and the LegacyParameter where the injection isn't working:
package com.depressio.domain.legacy;
public class LegacyParameter
{
#Inject private LegacyDAO legacyDAO;
....
public LegacyParameter(Parameter newParameter)
{
// NullPointerException when using the injected legacyDAO.
}
}
I've tried a few things, including:
Using an no-args constructor for LegacyParameter, then calling a populate method so I'm not using the injected DAO until after the object is constructed. This didn't work.
Injecting the LegacyDAO into the ParameterResource and passing it in. This worked, but isn't ideal since I have to pass it around a whole lot (which injection should help avoid, no?). It did prove that LegacyDAO is injectible... just not into LegacyParameter apparently.
Adding a #Service, #Component, or #Named annotation on LegacyParameter. All end up with the NullPointerException on the line I try to reference the injected legacyDAO.
What am I missing?
As Sotirios has pointed out, it can't work since you create a regular Java object and do not give Spring a chance to enhance it.
Either let Spring create objects for which you want to enjoy the Spring 'magic' (like setting #Inject dependencies etc).
Or create your own objects and set the dependencies yourself (yourObject.setDao(dao)).
That said, there are exceptional cases in which you still want to create your objects 'on the fly' by yourself but rely on Spring to inject dependencies to these objects. In this case you should call Spring explicitly:
LegacyParameter p = new LegacyParameter(...);
applicationContext.getAutowireCapableBeanFactory().autowireBean(p);
I don't think you really need it in your case.
(see this link inject bean reference into a Quartz job in Spring? for an example when this is really required).
In addition, I would advice to simplify your configuration.
Why do you use both xml-based and java-based configuration that do actually the same? In your example you could keep only one of them and have the same effect.

Categories

Resources