How to instantiate encapsulated object? - java

I am currently using spring. I created a restClient that uses a service based on another module. I am trying to instantiate this restClient but I always receive a null pointer exception. After investigation, it appears that the encapsulated attribute (objects) are not instantiating, their nested encapsulated neither.
This is the member variables, my class, the constructor and a method I am trying to call.
private OAuth2RestTemplate oAuth2RestTemplate;
private ConsumedDestinationModel consumedDestinationModel;
#Autowired
private DestinationService<ConsumedDestinationModel> destinationService ;
public DefaultSacRestClient()
{
consumedDestinationModel = getSacConsumedDestinationModel(getDestinationService().getAllConsumedDestinations());
oAuth2RestTemplate = configureOAuth2Credentials(getConsumedDestinationModel());
}
#Override
public List<Story> fetchStories() {
List<Story> stories = new ArrayList<>();
String endpoint = getConsumedDestinationModel().getUrl() + STORIES_URL;
stories.add(oAuth2RestTemplate.getForObject(endpoint, Story.class));
return stories;
}
in my constructor, both methods getSacConsumedDestinationModel() &
configureOAuth2Credentials() returns an object.
but the method getSacConsumedDestinationModel() uses the destinationService which is not instantiated. I dont understand why the destinationService member variable is not instantiated.
Here is the application context which corresponds only to the module I am working on. This application context is appended to the global application context of the application
<bean id="defaultSacRestClient" class="de.hybris.platform.sacintegrationbackoffice.client.impl.DefaultSacRestClient">
<property name="destinationService" ref="destinationService"/>
</bean>
<bean id="destinationService" class="de.hybris.platform.apiregistryservices.services.impl.DefaultDestinationService">
<property name="destinationDao" ref="destinationDao"/>
</bean>
<bean id="destinationDao" class="de.hybris.platform.apiregistryservices.dao.impl.DefaultDestinationDao">
<property name="flexibleSearchService" ref="defaultFlexibleSearchService"/>
<property name="modelService" ref="defaultModelService"/>
</bean>
Is it a bean configuration problem? Am I missing something? There is definitely something I do wrong.

Two possible problems:
Is the class annotated with #Component or #Service?
Some objects are instantiated with the constructor and some aren't.
Try
#Service
public class DefaultSacRestClient {
private final OAuth2RestTemplate oAuth2RestTemplate;
private final ConsumedDestinationModel consumedDestinationModel;
private final DestinationService<ConsumedDestinationModel> destinationService ;
public DefaultSacRestClient(DestinationService<ConsumedDestinationModel> destinationService) {
this.destinationService = destinationService;
this.consumedDestinationModel = getSacConsumedDestinationModel(destinationService.getAllConsumedDestinations());
this.oAuth2RestTemplate = configureOAuth2Credentials(getConsumedDestinationModel());
}
...
}

Related

pass parameter to reference with autowired

i want pass parameter to #autowired ref like
public CoreDao {
private String taskId;
private final String sql = "select ....."+getTaskId()+".....";
public CoreDao(String taskId){
if(taskId.length != 0){
this.taskId = taskId;
}else{
this.taskId = "0";
}
public getTaskId(){
return this.taskId;
}
}
xml is:
<bean id="coreDao" class="Coredao" scope="prototype">
<constructor-arg type="java.lang.String" value=""/>
</bean>
and the CoreService is
#service
CoreService implement ICoreService{
#Autowired
pirvate CoreDao;
}
and xml is
<bean id="coreService" class="CoreService" scope="prototype">
<property name="coreDao" ref="coreDao"/>
</bean>
and i want use getBean("coreService","123") to get the bean with dynamic reference of coreDao.
However,when i use getBean("coreService","123"),the exception is:
error creating bean with name "coreService" defined in file ....xml,could not resolve matching constructor (hint:specify index/type/name arguments for simple parameter to avoid ambiguities.
how could do that?thanks your help.
getBean(String, Object ...) is applicable to bean's constructors or factory methods.
Your CoreService should have CoreService(String s) constructor in order to use this method.
If you want to create many CoreService instances with different parameters, you can create a factory bean which creates all instances for you and puts them together, like
#Component
public class CoreServiceFactoryBean {
#Autowired ApplicationContext ctx;
public CoreService getBean(String param) {
CoreService coreService = ctx.getBean("coreService");
CoreDao coreDao = ctx.getBean("coreDao", parameter);
coreService.setCoreDao(coreDao);
return coreService;
}
}
This way, the logic of creating bean and using it remains separate. Using factories is pretty common to configure prototype scoped beans.

Spring's #Autowired not injecting a Map - am I even using it correctly?

I'm trying to add some Spring configuration to an existing utility class. It doesn't seem to work and I'm not sure why (my first time using these Spring options, I'm not even sure I'm doing it correctly).
The class in question
#Configurable(autowire=Autowire.BY_NAME, preConstruction=true)
public class DataUtility
{
private static final DataUtility INSTANCE = new DataUtility();
#Autowired(required=true) //This is the new field and annotation
private Map<String,String> dataFileMapping = new HashMap<String, String>();
public static DataUtility getInstance()
{
return INSTANCE;
}
private DataUtility()
{
//Do a bunch of setup work here
for (String s : dataFileMapping)
{
addDataToCache(dataFileMapping(s))
}
}
The spring config looks like this:
<context:annotation-config/>
<context:spring-configured/>
<bean id="util" class="com.myCompany.DataUtility">
<property name="dataFileMapping">
<map>
<entry key="data1" value="data/file1.dat"/>
<entry key="data2" value="data/file2.dat"/>
<entry key="data3" value="data/file3.dat"/>
</map>
</property>
</bean>
The problem is that when I step through my code in the debugger, I can see that dataFileMapping is empty. I'm not even sure if the spring config is even running.
I think you just need to add getters and setters for dataFileMapping
Also, remember that you can't iterate through the map in the constructor, spring wouldn't have had a chance to set it until after the constructor executes.
In addition to this, you can't make your constructor private and expect spring to be able to instantiate it.
The root of your problem is that you seem to be using a static reference INSTANCE to access the object. Spring is making a bean named 'util' and setting it up with your data, but that isn't becoming the object that INSTANCE points to. The initialization of static fields happens when the class is first loaded, long before spring ever gets a chance to create and inject beans.
You can sort of fake it like this, but of course attempts to access instance before bean initialization will fail:
#Configurable(autowire=Autowire.BY_NAME, preConstruction=true)
public class DataUtility
{
private static final DataUtility INSTANCE = null;
#Autowired(required=true) //This is the new field and annotation
private Map<String,String> dataFileMapping = new HashMap<String, String>();
public static DataUtility getInstance()
{
return INSTANCE;
}
public postInit()
{
INSTANCE = this;
//Do a bunch of setup work here
for (String s : dataFileMapping)
{
addDataToCache(dataFileMapping(s))
}
}
<bean id="util" class="com.myCompany.DataUtility" init-method="postInit">
<property name="dataFileMapping">
<map>
<entry key="data1" value="data/file1.dat"/>
<entry key="data2" value="data/file2.dat"/>
<entry key="data3" value="data/file3.dat"/>
</map>
</property>
</bean>

Cleaner way to get new instance of an autowired field that is prototype in nature

I faced this issue, while trying to autowire a runnable class and creating different instances of it in different call and keeping it in an array.
xml configuration is :
<bean name="threadName" Class="ABC" scope="prototype" />
In my code, I am trying something like this:
public class ThreadHandler{
#Autowired
private ABC threadName;
//getter
ABC getThreadName(){
return threadName;
}
public void someFunction(){
List<ABC> abc = new ArrayList(ABC>();
for (int i=0;i<SOME_CONST;i++){
ABC tName = getThreadName();
abc.add(tName);
tName.start();
}
}
}
Let ABC be a class which is Thread/Runnable/Callable.
In this way, it throws java.lang.IllegalThreadStateException.
But, it works fine, if I use ABC tName =appContext.getBean("threadName",ABC.class);
Why does it happen?
Don't we get a new instance while trying to get an object from getMethod?
There is much better practice when you need to create Runnable/Callable and inject it into applicationContext it's called look up method:
Let's consider that all Runnable/Callable classes are #Prototype and #Lazy
#Component(value="task")
#Scope(value="prototype")
#Lazy(value=true)
public class Task implements Runnable {
public void run(){
.....
}
}
Now you need to Create Look up method factory:
<bean id="taskFactory" class="x.y.z.TaskFactory">
<lookup-method name="createTask" bean="task"/>
</bean>
Now let's implement TaskFactory itself which is abstract class and have one abstract method :
#Component(value="taskFactory")
public abstract class TaskFactory {
public abstract Task createTask();
}
Here comes the magic:
public class ThreadHandler{
#Autowired
private TaskFactory taskFactory;
public void someFunction(){
Runnable task = taskFactory.createTask();
taskExecutor.execute(task);
}
}
Every time you are calling createTask() method of taskFactory singleton object. you will receive completely new instance of your prototype object.
P.S: don't forget to add
<context:annotation-config />
<context:component-scan base-package="x.y.z"></context:component-scan>
to enable Annotations correctly.
hope it Helps.
No, you don't get a new object, just by accessing a field that holds a reference to a bean scoped as Prototype. Spring doesn't have any way to replace your instance level reference with a new reference based just on field access. It's set once by the autowiring and then it's just a reference to that one object. If you want it to actually create a new one you need to use getBean as you observed.
You can tell Spring to override your get method and replace it with a 'getBean' using method injection, to get the Spring dependencies out of your bean:
<bean id="threadHandler" class="com.stackexchange.ThreadHandler">
<lookup-method name="getThreadName" bean="threadName"/>
</bean>

spring bean with dynamic constructor value

I need to create an Object which is in-complete without the constructor argument. Something like this
Class A {
private final int timeOut
public A(int timeout)
{
this.timeOut = timeout;
}
//...
}
I would like this Bean to be spring managed, so that I can use Spring AOP later.
<bean id="myBean" class="A" singleton="false">
</bean>
However my bean needs timeout to be passed as a dynamic value - is there a way to create a spring managed bean with dynamic value being injedcted in the constructor?
BeanFactory has a getBean(String name, Object... args) method which, according to the javadoc, allows you to specify constructor arguments which are used to override the bean definition's own arguments. So you could put a default value in the beans file, and then specify the "real" runtime values when required, e.g.
<bean id="myBean" class="A" scope="prototype">
<constructor-arg value="0"/> <!-- dummy value -->
</bean>
and then:
getBean("myBean", myTimeoutValue);
I haven't tried this myself, but it should work.
P.S. scope="prototype" is now preferable to singleton="false", which is deprecated syntax - it's more explicit, but does the same thing.
Two options spring (no pun intended) to mind:
1. create a timeout factory, and use that as the constructor parameter.
You can create a bean which implements FactoryBean, and it's job is to create other beans. So if you had something that generates salt's for encryption, you could have it return from getObject() a EncryptionSalt object. In your case you're wanting to generate Integers.
Here is an example: http://www.java2s.com/Code/Java/Spring/SpringFactoryBeanDemo.htm
2. create a timeout bean that wraps an int that's dynamically set, and leave that in the "prototype" state so it's created each time
Instead of going to the hassle of creating a factory, the EncryptionSalt object could just be declared as a prototype bean, so when it's injected a new object is created each time. Place the logic into the constructor or somewhere else.
It somewhat depends what value you want the timeout to actually be.
Do it explicitly:
interface Bean {
void setTimeout(int timeout);
}
class BeanImpl implements Bean {
private int timeout;
#Override
public void setTimeout(int timeout) {
this.timeout = timeout;
}
...
}
<bean id="bean" class="BeanImpl" scope="prototype">
...
<!-- Nothing about timeout here -->
...
</bean>
class Client {
private Bean bean;
public void setBean(Bean bean) {
this.bean = bean;
}
...
public void methodThatUsesBean() {
int timeout = calculateTimeout();
bean.setTimeout(timeout);
...
}
}

Logging bean id into log4j logfile without BeanNameAware interface

Given a set of classes wired together by spring. There are several classes that are used with different configuration in multiple instances in the environment. They have different beanid of course.
The problems:
When they make log entries, we dont know exactly which bean made the log, since the log4j displays the classname only
I know that I could use logger instantiated by spring InitializationBean+BeanNameAware interface methods, but I do not want to do it, since I do not want to implement them in all classes
The solution could be:
Having some effect on bean factory to store the id of the beans in a map with the bean reference (key is the ref, name is the value)
Creating an aspect to be applied on every method, that would set an "BeanName" MDC entry in Log4j before the call, and would restore it to the previous value after the call. Meanwhile the previous beannames could be stored in a threadlocal in a stack.
The questions:
How can I change/configure the bean factory to do this trick for me? Is there any customization point I could use to this aim?
How can I avoid memory leaks in the map in the beanid registry? Maybe the registry is not needed at all, if somehow spring can look up the id for a reference.
Do you have any better idea, that would not result in changing ten thousand classes?
Thanks in advance.
UPDATE:
- Does anyone have solution for the prototype beans?
I have managed to hack something together based on this Spring AOP Example.
I am not yet up to speed with Spring 3 so I have implemented this using Spring 2.5 - I dare say there are more elegant ways of achieving what you want. I have implemented this using System.out's for simplicity but these could easily be converted to log4j calls.
Initially I create a map between the Spring's bean names and the string representation of the object (InitBean). This map is used inside the MethodInterceptor - I did try making the MethodInterceptor an InitializingBean but the MethodInterceptor stopped working for some reason.
Performing an equals between the bean passed in via the MethodInterceptor and the other beans in the application context did not work. e.g. by using something like "ctx.getBeansOfType(GoBean.class)" inside the MethodInterceptor. I presume this is because the object passed in via the MethodInvocation was a GoBean whereas objects obtained from the application context at this point are proxied (e.g. something like example.GoBean$$EnhancerByCGLIB$$bd27d40e).
This is why I had to resort to a comparison of object string representations (which is not ideal). Also I specifically do not want to activate the MethodInterceptor logic when calling the "toString" method on an object (as since I'm using toString elsewhere leads to infinite loops and StackOverflow).
I hope this is useful,
applicationContext.xml
<beans>
<bean name="initBean" class="example.InitBean"/>
<bean name="methodLoggingInterceptor" class="example.MethodLoggingInterceptor">
<property name="initBean" ref="initBean"/>
</bean>
<bean name="proxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>go*</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>methodLoggingInterceptor</value>
</list>
</property>
</bean>
<bean name="goBean1" class="example.GoBean" />
<bean name="goBean2" class="example.GoBean" />
<bean name="goBean3" class="example.GoBean" />
</beans>
GoBean.java
public class GoBean {
public void execute(){
System.out.println(new Date());
}
}
SimpleTestClass.java
public static void main( String[] args ){
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ArrayList<GoBean> goBeans = new ArrayList<GoBean>();
goBeans.add((GoBean) ctx.getBean("goBean1"));
goBeans.add((GoBean) ctx.getBean("goBean2"));
goBeans.add((GoBean) ctx.getBean("goBean3"));
for(GoBean g: goBeans){
g.execute();
}
}
InitBean.java
public class InitBean implements ApplicationContextAware, InitializingBean {
private ApplicationContext ctx;
private Map<String, String> beanMap = new HashMap<String,String>();
public void setApplicationContext(ApplicationContext ac) throws BeansException {
ctx = ac;
}
public void afterPropertiesSet() throws Exception {
for(String beanName: ctx.getBeanNamesForType(GoBean.class)){
beanMap.put(ctx.getBean(beanName).toString(), beanName);
}
}
public Map<String,String> getBeanMap(){
return beanMap;
}
}
MethodLoggingInterceptor.java
public class MethodLoggingInterceptor implements MethodInterceptor{
private InitBean initBean;
public Object invoke(MethodInvocation method) throws Throwable {
if (!"toString".equals(method.getMethod().getName())) {
StringBuilder sb = new StringBuilder();
Object obj = method.getThis();
if (obj instanceof GoBean) {
Map<String,String> beanMap = initBean.getBeanMap();
String objToString = obj.toString();
if (beanMap.containsKey(objToString)) {
System.out.println(beanMap.get(objToString));
sb.append("bean: ");
sb.append(beanMap.get(objToString));
sb.append(" : ");
}
}
sb.append(method.getMethod().getDeclaringClass());
sb.append('.');
sb.append(method.getMethod().getName());
System.out.println(sb.toString() + " starts");
Object result = method.proceed();
System.out.println(sb.toString() + " finished");
return result;
} else {
return method.proceed();
}
}
public void setInitBean(InitBean ib) {
this.initBean = ib;
}
}

Categories