How setter works inside Spring Framework #2? - java

Sorry for the copy of this article. I'd want to comment it, but without 50 scores of reputation I can`t comment, so...
I have
private boolean stopLoggingIntoDb;
....
public void setStopLoggingIntoDb(String stopLoggingIntoDb) {
this.stopLoggingIntoDb = BooleanUtils.toBoolean(stopLoggingIntoDb.replaceAll("[^A-Za-z]", ""));
logger.warn("Logging into SiebelMethodLogs is " + (!this.stopLoggingIntoDb ? "ON" : "OFF"));
}
and XML
<bean id="siebelMethodProcessor" class="com.entities.utils.Logger">
<property name="logService" ref="logService"/>
<property name="stopLoggingIntoDb" value="${monitor.siebel.stopLogging}"/>
</bean>
In that case, is everything Ok, but If I change the property in setter method from stopLoggingIntoDb to stopLog and change the property name in XML also to stopLog or not, Spring said me Invalid property 'stopLoggingIntoDb' or Bean property 'stopLog' is not writable.
Because of that, my question is What the Spring does with setter method? Which value is injected and which field/property is searching while gets the injection?

As can be seen in this example in the Spring Documentation, the name attribute of the <property> element must match a setter method. The name of the methods parameter and the name of the field doesn't matter.
Examples of dependency injection
The following example uses XML-based configuration metadata for setter-based DI. A small part of a Spring XML configuration file specifies some bean definitions:
<bean id="exampleBean" class="examples.ExampleBean">
<!-- setter injection using the nested ref element -->
<property name="beanOne">
<ref bean="anotherExampleBean"/>
</property>
<!-- setter injection using the neater ref attribute -->
<property name="beanTwo" ref="yetAnotherBean"/>
<property name="integerProperty" value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
public class ExampleBean {
private AnotherBean beanOne;
private YetAnotherBean beanTwo;
private int i;
public void setBeanOne(AnotherBean beanOne) {
this.beanOne = beanOne;
}
public void setBeanTwo(YetAnotherBean beanTwo) {
this.beanTwo = beanTwo;
}
public void setIntegerProperty(int i) {
this.i = i;
}
}
Notice how name="integerProperty" matches up to the setIntegerProperty() method, even though the parameter is named i and the field is named i.

Related

Rest Spring beans using xml Configuration

I am using Rest Spring beans using xml Configuration.
I am trying to access variables which are initailized by beans using REST urls. But i am not able to fetch values. values fetched are null.
Is there anyway to initalize values and keep them intact and access them when i make call using urls.
Please suggest some way.
TIA
Edit:
Model:
#Repository
public class Topic{
private Integer id;
private String name;
//Getter and setter with constructor
}
Controller Class:
#RestController
#Singleton
public class TopicController{
#Autowired
private TopicService topicService;
public void setTopicService(TopicService topicService) {
this.topicService = topicService;
}
#RequestMapping("/topics")
public List<Topic> getAllTopics() {
System.out.println("in get all topics");
return topicService.getAllTopics();
}
}
ServiceClass:
#Service
public class TopicService {
#Autowired
private List<Topic> allTopics ;
public TopicService() {
}
public List<Topic> getAllTopics() {
return allTopics;
}
public void setAllTopics(List<Topic> allTopics) {
this.allTopics = allTopics;
}
}
Bean.xml
<bean name="topicService" id="topicService"
class="org.springtest.service.TopicService">
<property name="allTopics">
<list>
<bean class="org.springtest.model.Topic">
<property name="id" value="20" />
<property name="name" value="topic20" />
</bean>
<bean class="org.springtest.model.Topic">
<property name="id" value="30" />
<property name="name" value="Topic30" />
</bean>
</list>
</property>
</bean>
<bean id="topicController"
class="org.springtest.controller.TopicController"
scope="singleton">
<property name="topicService" ref="topicService"></property>
</bean>
output of
/localhost:8080/topics is:
{"id":null,"name":null}
Main class:
public static void main(String[] args) {
SpringApplication.run(CourseApiApp.class, args);
ApplicationContext context = new
ClassPathXmlApplicationContext("main/resources/Bean.xml");
TopicController tc= new TopicController();
System.out.println(tc.getAllTopics().size());// throwing nullpointerexception as topicService is null
}
I suggest you take a look at Jersey. It's a REST framework, one of the best in my opinion. Be sure to use a Snapshot of the last version of Jersey (I believe it's version 3), as it will have full support of Spring.
It's usage is simple.
A method controller will have 5 lines tops. It also encourages users to the best practices of a RESTful API. Such as defining the location header on a successful post, link headers referencing paging in a collection get, amongst others.
With Maven or Gradle in your project, integrating Jersey will take you 5 minutes.
I use it over Spring because it's sole purpose is implementing a REST API, while Spring has it simply as a feature.
I apologize for my lack of solution, just ask me if you need help getting started.
Andrés
That's because in the main method you have: TopicController tc= new TopicController(); which is wrong. The TopicController should be instantiated by Spring in your Main class using dependency injection. Above the main method you should write
#Autowired
private TopicController tc;, and remove the "tc" variable in the main method.

Handling Context In Spring

I'm working on a small project and I'm looking for a good way to handle context in spring. I find myself creating a context holder class to hold my properties using setter injection. The problem I'm having with this is that I'm grabbing a context object and passing it around. I'm looking for a design pattern or something that can help me do this in a cleaner way. As a simple example let's say I'm currently doing something like the below, where the fields are injected through setter injection and I'm looking for a better way to inject the properties Also, pretend I had a large amount of properties, too large to use something like #Value cleanly:
public class MyContext{
private String configItem1;
private String configItem2;
private String configItem3;
public void setConfigItem1(String configItem1){
this.configItem1 = configItem1;
}
public void setConfigItem2(String configItem2){
this.configItem2 = configItem1;
}
public void setConfigItem3(String configItem3){
this.configItem3 = configItem1;
}
}
Sample spring context:
<bean id="appProperties"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:my-app.properties</value>
</list>
</property>
</bean>
<bean id="myContext" class="these.are.not.the.droids.you.are.looking.for.context.MyContext" >
<property name="configItem1" value="${some.item.1}" />
<property name="configItem2" value ="${some.item.2}"/>
<property name="configItem3" value="${some.item.3}" />
</bean>
Have you considered simply using a Map to store the values? Java is inherently a verbose language. So I guess you don't have much choice otherwise.
http://www.java2s.com/Tutorial/Java/0417__Spring/FillMap.htm
If your config values are specific to a request, then you can use a ThreadLocal (API for ThreadLocal) which can hold values across the layers in an "invocation context". You can populate this ThreadLocal varaible in your controller and use it any layer in the same invocation chain.
If your settings are applicable across requests then you can use ApplicationContext to store the values. You can access ApplicationContext like this in Spring -
#Autowired
private ApplicationContext appContext;

How to Inject Spring values to Hibernate Type Definition class

This is a Spring Hibernate implementation. I have defined a custom Type definition where I need to pass
one default value to my custom Type Definition class as below.
But the value is null please help me what am I missing here ?
#TypeDef(name = "customString", typeClass = com.mydomain.EncryptString.class)
public class employee{
private String empId;
private String empName;
#Type(type="customString")
private String passportNumber;
//setter and getters
}
public class EncryptString mplements UserType{
private String password; // inject via spring configurations
#Override
public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException {
String encryptedPassport = rs.getString(names[0]);
System.out.println(names.length);
System.out.println("##"+password); // This null ????
return ""
}
//password getters and setters methods
}
Spring configurations
<bean id="customString"
class="com.mydomain.EncryptString">
<property name="password" value="password" />
</bean>
value of the password password in nullSafeGet() method it prints Null. How to make it
inject ? I expect Spring will load all the given default values and it instantiate values
when the EncryptString class call via Hibernate annotation.
Updating my question with findings
I have saw a example where TypeDef pass spring bean id as a parameter as below.
#TypeDef(name = "encryptedString", typeClass =
org.jasypt.hibernate.type.EncryptedStringType.class, parameters = { #Parameter(name
= "encryptorRegisteredName", value = "hibernateStringEncryptor") })
Spring configuration is
<bean id="hibernateStringEncryptor"
class="org.jasypt.hibernate.encryptor.HibernatePBEStringEncryptor">
<property name="registeredName" value="hibernateStringEncryptor" />
<property name="password" value="password" />
<property name="saltGenerator">
<bean class="org.jasypt.salt.FixedStringSaltGenerator">
<property name="salt" value="salt"/>
</bean>
</property>
hibernateStringEncryptor configuration is injected via type def passing the bean id as a
parameter. I went through the code http://www.jasypt.org/download.html but could not figure
out the way the bean get injected.
I think you need to use #Configurable annotation because Spring doesn't instantiate the custom types, Hibernate does and Spring doesn't know about those instances. This is the section in the documentation that describes the scenario. I haven't used this approach myself, but #Configurable would be the first thing I'd try.
Basically, you need to annotate your EncryptString class with #Configurable, to add spring-aspect.jar to your project's classpath, to add <context:spring-configured/> to your xml config file and to enable AspectJ weaving. The documentation gives quite some details regarding this.

Spring and Hibernate Runtime error

Below error is seen on my eclipse. I am just trying to save a terminalgroup object and was getting an error about TerminalGroupImpl not found. So I created a TerminalGroupImpl.java to be a hibernate file that has the #Entity for the terminal_group table. I have a TerminalGroupDaoHibernate.java file that using the TerminalGroupImpl.class to execute queries on the terminal_group table.
Please if someone can tell me what is wrong with my code and/or what I can do to figure out what is wrong?
Error
Invalid property 'terminalGroupDaoHibernate' of bean class
[com.ccadllc.dac.model.consumer.terminalgroups.TerminalGroupServiceImpl]:
Bean property 'terminalGroupDaoHibernate' is not writable or has an invalid setter method.
Does the parameter type of the setter match the return type of the getter?
Here is my applicationContext.xml file:
<!-- Terminal Group Service -->
<bean id="com.ccadllc.dac.model.consumer.terminalgroups.TerminalGroupService"
class="com.ccadllc.dac.model.consumer.terminalgroups.TerminalGroupServiceImpl">
<property name="terminalGroupDao"
ref="com.ccadllc.dac.model.consumer.terminalgroups.dao.TerminalGroupDao"/>
<property name="terminalGroupComponentDao"
ref="com.ccadllc.dac.model.consumer.terminalgroups.dao.TerminalGroupComponentDao"/>
</bean>
<bean id="com.ccadllc.dac.model.consumer.terminalgroups.TerminalGroupImpl"
class="com.ccadllc.dac.model.consumer.terminalgroups.TerminalGroupImpl" abstract="true">
<property name="terminalGroupDaoHibernate"
ref="com.ccadllc.dac.model.consumer.terminalgroups.dao.TerminalGroupDaoHibernate"/>
</bean>
<bean id="com.ccadllc.dac.model.consumer.terminalgroups.dao.TerminalGroupDao"
class="com.ccadllc.dac.model.consumer.terminalgroups.dao.TerminalGroupDaoHibernate">
<property name="messageService" ref="com.ccadllc.dac.messaging.MessagingService" />
</bean>
under hibernate.annotated.classes:
<value>com.ccadllc.dac.model.consumer.terminalgroups.TerminalGroupImpl</value>
TerminalGroupServiceImpl.java
Getter/Setter in TerminalGroupServiceImpl.java:
private TerminalGroupDao terminalGroupHibernateDao;
/**
* #param TerminalGroupHibernateDao The TerminalGroupHibernateDao to set.
*/
#Required
#Transactional
public void setTerminalGroupHibernateDao(final TerminalGroupDao terminalGroupHibernateDao)
{
this.terminalGroupHibernateDao = terminalGroupHibernateDao;
}
#Required
#Transactional
public TerminalGroupDao getTerminalGroupHibernateDao()
{
return terminalGroupHibernateDao;
}
You are trying to set terminalGroupDaoHibernate property instead of terminalGroupHibernateDao.
The property you have defined in the xml is "terminalGroupDaoHibernate", but the setter in your service impl's name is "setTerminalGroupHibernateDao". There is typo error. The setter name should be "setTerminalGroupDaoHibernate"
You should not add the #Required annotation on a getter. Also, in your bean xml, you use the property name terminalGroupDao but your setter has the name setTerminalGroupHibernateDao rather than setTerminalGroupDao.

Optional Spring bean references

In my application I am using ContextLoaderListener to load context files from many jars using:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:META-INF/contextBeans.xml</param-value>
</context-param>
This means I can reference beans from other jars without doing import.
In the application there are multiple deployment options and in some deployments jars can be excluded. To support that I would like some bean references to be optional. For example:
<bean id="mainAppBean" class="com.someapp.MyApplication">
<constructor-arg index="0" ref="localBean"/>
<constructor-arg index="1" ref="optionalBeanReference1"/>
<constructor-arg index="2" ref="optionalBeanReference2"/>
</bean>
In the example above I would like to have optionalBeanReference1 equal null if the reference was not found (mark it optional in some way)
Can this be done in Spring? or what method do you recommend for handling dynamic references?
My best guess is to use autowire-ing with required false. Don't know how you can express this in XML but using annotation configuration this would look like:
#Autowired(required=false)
With recent versions of Spring (tested with spring 4.1) and Java Configuration and Java 8, you can use Optional in parameters, and are only autowired if available.
#Autowired
public MyApplication(Optional<YourOptionalObject> maybeObject) {
// do something with the optional autowired
}
what method do you recommend for handling dynamic references?
I think #cristian's #Autowired answer is a good one. That will call the setter methods if the beans of that type are available. However, if you have multiple beans of the same type, I believe Spring throws an exception. If you cannot use #Autowired for this or some other reason, I see a couple of solutions:
You could make your class ApplicationContextAware and lookup the beans in the context yourself:
public void setApplicationContext(ApplicationContext applicationContext) {
if (applicationContext.containsBean("optionalBeanReference1")) {
setOptionalBeanReference1(
(OptionalBeanReference1)applicationContext.bean(
"optionalBeanReference1");
}
...
}
You could invert the dependency. Each of the optional classes could set themselves on the mainAppBean. I use this in certain situations when a direct dependency would cause loops or other problems.
<bean id="optionalBeanReference1" class="com.someapp.SomeClass">
<constructor-arg index="0" ref="mainAppBean"/>
</bean>
Then in the SomeClass:
public SomeClass(com.someapp.MyApplication mainAppBean) {
mainAppBean.setOptionalBeanReference1(this);
}
You could stay with your direct dependency and then either import a file with the beans defined or import another file where you define the beans as having null values by using a factory bean. See this factory code.
Good luck.
There's no built-in mechanism for this. However, you could write a pretty trivial FactoryBean implementation to do this for you, something like this:
public class OptionalFactoryBean extends AbstractFactoryBean<Object> implements BeanNameAware {
private String beanName;
#Override
public void setBeanName(String beanName) {
this.beanName = BeanFactoryUtils.originalBeanName(beanName);
}
#Override
protected Object createInstance() throws Exception {
if (getBeanFactory().containsBean(beanName)) {
return getBeanFactory().getBean(beanName);
} else {
return null;
}
}
#Override
public Class<?> getObjectType() {
return null;
}
}
You can then use it like this:
<bean id="mainAppBean" class="com.someapp.MyApplication">
<constructor-arg index="0" ref="localBean"/>
<constructor-arg index="1">
<bean name="optionalBeanReference1" class="com.someapp.OptionalBeanFactory"/>
</constructor-arg>
<constructor-arg index="2">
<bean name="optionalBeanReference2" class="com.someapp.OptionalBeanFactory"/>
</constructor-arg>
</bean>
Given that the bean references in your XML config are defined via expression language (EL) you can do the following:
<property name="cache" value="#{getObject('optionalCache')}" />
which makes use of the BeanExpressionContext.getObject() method. See here for more details.

Categories