I have the next simple application(class Message has only one method which prints incoming message and has no interest for the question):
package messager.spring;
public class User {
private Messenger misiger;
private String name;
public User(String name) {
this.name = name;
}
public void setMessenger(Messenger messinger) {
this.misiger = messinger;
}
public void send(String mess) {
String message = name + " sent message " + "'" + mess + "'";
misiger.send(message);
}
// public String getname() {
// return name;
// }
}
Main class:
package messager.spring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) context.getBean("user");
user.send("testing3...");
}
}
Spring configuration file:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="user" class="messager.spring.User" autowire="byName">
<constructor-arg type="java.lang.String" value="Vova2"/>
</bean>
<bean id="messenger" class="messager.spring.MobileMessenger"/>
</beans>
I used autowiring for class User autowiring Messanger class. According to documentation :
When ByName is used, it then tries to match and wire its properties with the beans defined by the same names in the configuration file. If matches are found, it will inject those beans otherwise, it will throw exceptions.
This configuration works but I dont understand why((( I dont have property with name messenger inside User class((( I changed it on purpose to misiger. And it still works. It seems that bean id directly depends not on property name, but on setter name!!! Is it so?
YES, you are right. As described here :
Spring will lowercase the first letter after “set” in the method name and use the rest of the method name as-is for deducing the property name.
So not the member variable but the setter defines the property name.
That's how JavaBeans work, by looking at naming conventions.
The underlying reference isn't necessarily relevant.
The name of your property is messenger because there's a getter called that.
Related
I have the following bean:
package com.test;
#Component
public class Sample{
String modified = null;
#Value("${url}")
private String url;
public Sample(){
System.out.println(url );
if(baseUrl.equals(""){
throw new RuntimeException("missing");
}
else{
modified = "test"+url;
}
}
}
I have added:
<context:annotation-config />
<context:property-placeholder location="classpath:test.properties"/> & <context:component-scan base-package="com.test"/>
and trying to access above "modified" field as below
<bean id="url" class="java.lang.String">
<constructor-arg value="#{sample.modified}" />
</bean>
in my application context. But I keep getting the following error:
Field or property 'sample' cannot be found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext'
Not sure why i get this error?
When Spring creates the object it uses the default constructor. It can't set the property until after it constructs it. Instead of what you have, try this to see if the value is being set.
#PostConstruct
public void init(){
System.out.println(url );
if(baseUrl.equals(""){
throw new RuntimeException("missing");
}
}
JustinKSU's answer is right. You have another option: inject value via constructor using #Autowired:
#Component
public class Sample {
#Autowired
public Sample(#Value("${url}") String url) {
System.out.println(url);
if(url.equals("") {
throw new RuntimeException("missing");
}
}
}
Spring autowire byName not working as expected.
public class SpellChecker {
public SpellChecker() {
System.out.println("Inside SpellChecker constructor." );
}
public void checkSpelling() {
System.out.println("Inside checkSpelling." );
}
}
public class TextEditor {
private SpellChecker spellChecker1;
private String name;
public void setSpellChecker( SpellChecker spellChecker1 ){
this.spellChecker1 = spellChecker1;
}
public SpellChecker getSpellChecker() {
return spellChecker1;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void spellCheck() {
System.out.println(" TextEditor name is " +name);
spellChecker1.checkSpelling();
}
}
public class TextEditorMain {
public static void main(String args[]) throws InterruptedException{
ApplicationContext context = new
ClassPathXmlApplicationContext("Beans.xml");
TextEditor tEditor = (TextEditor) context.getBean("textEditor");
tEditor.spellCheck();
}
}
Spring beans configuration:
<bean id = "spellChecker1" class = "com.spring.beans.SpellChecker">
</bean>
<bean id = "textEditor" class = "com.spring.beans.TextEditor" autowire="byName">
<property name = "name" value = "text1"/>
</bean>
When I give spellChecker1 as bean id it is not working. Below are the console o/p,
Inside SpellChecker constructor.
TextEditor name is text1
Exception in thread "main" java.lang.NullPointerException
at com.spring.beans.TextEditor.spellCheck(TextEditor.java:26)
at com.spring.main.TextEditorMain.main(TextEditorMain.java:15)
Bean id and reference name both are same spellChecker1 but still not working. But the strange thing is if I change the bean id in xml from spellChecker1 to spellChecker the code is working and giving below o/p,
Inside SpellChecker constructor.
TextEditor name is text1
Inside checkSpelling.
So why dependency is not added when I am using spellChecker1 ?
It actually works as designed. Your property is named spellChecker not spellChecker1. You have a field named spellChecker1.
The name of the field is not the same as the name of a property. A name of the property is defined by the get and set methods available on a class. As you have a setSpellChecker (and the corresponding getter) there is a property named spellChecker.
All of this is written down in the JavaBeans Specification (which was written somewhere in 1998!)
Basically properties are named attributes associated with a bean that can be read or written by calling appropriate methods on the bean. Thus for example, a bean might have a foreground property that represents its foreground color. This property might be read by calling a Color getForeground() method and updated by calling a void setForeground(Color c) method.
Source the JavaBeans Specification.
I have a simple example program here:
package com.test;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class Main {
public static void main(String[] args) throws InterruptedException {
try {
FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("TestBeanFile.xml");
Object o = context.getBean("AInstance");
}
catch (Throwable e) {
e.printStackTrace();
}
Thread.sleep(Long.MAX_VALUE);
}
private static class A implements InitializingBean {
private B myB;
public A() {
System.out.println("A constructor");
}
public void setB(B aB) {
myB = aB;
}
#Override
public void afterPropertiesSet() throws Exception {
System.out.println("A aps");
}
}
private static class B implements Runnable, InitializingBean {
private C myC;
private volatile boolean exit = false;
public B() {
System.out.println("B constructor");
}
public void setC(C aC) {
myC = aC;
}
#Override
public void afterPropertiesSet() throws Exception {
System.out.println("B aps");
if (myC == null) throw new IllegalArgumentException("C cannot be null");
new Thread(this).start();
}
public void exit() {
exit = true;
}
#Override
public void run() {
while (!exit) {
System.out.println(myC.getValue());
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
private static class C implements InitializingBean {
private String value = "C's value";
public C() {
System.out.println("C constructor");
}
public String getValue() {
return value;
}
#Override
public void afterPropertiesSet() throws Exception {
System.out.println("C aps");
}
}
}
And here is a simple XML to bean load them which intentionally has an incorrect fully qualified name to the A class. This should mean that C B and A dont get constructed.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-stream="http://www.springframework.org/schema/integration/stream"
xmlns:int-ip="http://www.springframework.org/schema/integration/ip"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-2.1.xsd
http://www.springframework.org/schema/integration/stream http://www.springframework.org/schema/integration/stream/spring-integration-stream-2.1.xsd
http://www.springframework.org/schema/integration/ip http://www.springframework.org/schema/integration/ip/spring-integration-ip-2.1.xsd">
<bean id="CInstance" class = "com.test.Main.C" />
<bean id="BInstance" class = "com.test.Main.B">
<property name="C" ref="CInstance" />
</bean>
<bean id="AInstance" class = "com.test.Main.A1">
<property name="B" ref="BInstance"/>
</bean>
</beans>
When you run this application using the above XML C and B DO get constructed but A doesnt. It will produce the following output (omitting the stack trace when the exception is thrown, but I assure you A does not get constructed):
C constructor
C aps
B constructor
B aps
C's value
C's value
C's value
....... // one a second
If you modify the XML to look like this:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-stream="http://www.springframework.org/schema/integration/stream"
xmlns:int-ip="http://www.springframework.org/schema/integration/ip"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-2.1.xsd
http://www.springframework.org/schema/integration/stream http://www.springframework.org/schema/integration/stream/spring-integration-stream-2.1.xsd
http://www.springframework.org/schema/integration/ip http://www.springframework.org/schema/integration/ip/spring-integration-ip-2.1.xsd">
<bean id="AInstance" class = "com.test.Main.A1">
<property name="B" ref="BInstance"/>
</bean>
<bean id="BInstance" class = "com.test.Main.B">
<property name="C" ref="CInstance" />
</bean>
<bean id="CInstance" class = "com.test.Main.C" />
</beans>
The only output you get is the stack trace, and the B and C objects dont get constructed at all.
This seems like its a bug in spring. I dont understand why the marshaling of the objects, and the constructors / afterpropertiesSet methods which are run depend on the order of their appearance in the XML. What this means for me, is that when I have classes which construct threads in their constructors / after properties set methods, if I'm not careful about how I order the elements in the XML I can end up leaking resources if my only reference to them is, in this example, the A class. Because it fails construction in both cases.
So, is this a bug, or is this some feature that I dont understand? If this is a feature, what reason would they have to make the order of marshaling dependent on the XML file, instead of the object graph of the bean definitions?
Spring first reads the <bean> and other elements in the XML configuration and creates appropriate BeanDefinition objects defining them.
It then has to initialize them. To do this, it has to decide on an order. The order of initialization is undefined, unless a bean depends on another or there is a mix of #Order, implementations of Ordered and a few others (depends on the case).
In your first example, CInstance is initialized first. Then BInstance is initialized. Part of its initialization involves invoking its afterPropertiesSet() method which launches a non-daemon thread. Then Spring attempts to initialize AInstance and fails.
In your second example, Spring attempts to initialize AInstance first. It fails immediately, with no change to start a second thread.
Note that in a declaration like
<bean id="AInstance" class="com.example.Spring.A1">
<property name="B" ref="BInstance" />
</bean>
although AInstance depends on BInstance, the actual instance needs to be initialized before any property setters can be invoked to assign BInstance to B. So Spring begins the initialization of AInstance by instantiating the class. If it fails, the entirety of context refresh fails. If it passes, it will then initialize the BInstance bean and use it to set the B property.
I have a web application developped in Java 1.5 with Spring framework. Application contains "dashboards" which are simple pages where a bunch of information are regrouped and where user can modify some status. Managers want me to add a logging system in database for three of theses dashboards. Each dashboard has different information but the log should be traced by date and user's login.
What I'd like to do is to implement the Strategy pattern kind of like this :
interface DashboardLog {
void createLog(String login, Date now);
}
// Implementation for one dashboard
class PrintDashboardLog implements DashboardLog {
Integer docId;
String status;
void createLog(String login, Date now){
// Some code
}
}
class DashboardsManager {
DashboardLog logger;
String login;
Date now;
void createLog(){
logger.log(login,now);
}
}
class UpdateDocAction{
DashboardsManager dbManager;
void updateSomeField(){
// Some action
// Now it's time to log
dbManagers.setLogger = new PrintDashboardLog(docId, status);
dbManagers.createLog();
}
}
Appcontext.xml :
<bean id="dashboardManagers" class="...DashboardManagers" />
In this solution I'm therefore not using dependency injection. Is it "correct" (good practice, performance, ...) to do it this way ? Is there a better way where I could use DI ?
Note :I did not write basic stuff like constructors and getter/setter.
Your solution will create a new instance of PrintDashboardLog for each call to updateSomeField(). This might take up unnecessary time/memory/GC-effort. Also, from a design perspective it makes sense if there is one DashboardLog for each Dashboard, not a new one for each call.
I think it may be a good idea to use aspects for which Logging is one of the exemplary usecases. Something like:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<bean id="loggingAspect" class="com.yourcompany.yourapplication.aspects.DashboardLogAspect" />
<aop:aspectj-autoproxy>
<aop:include name="loggingAspect" />
</aop:aspectj-autoproxy>
</beans>
package com.yourcompany.yourapplication.aspects;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
#Aspect
public class DashboardLogAspect {
#Around("execution(* com.yourcompany.yourapplication..*Action+.*(..)) && target(target)")
public Object logActionCall(ProceedingJoinPoint pjp, Object target) throws Throwable {
long before = System.nanoTime();
Object returnValue = pjp.proceed();
long after = System.nanoTime();
long durationNs = after - before;
String logMsg = target.getClass() + "." + pjp.getSignature().toShortString() + " (" + durationNs + " ns)";
// TODO: store the log message in your database
System.out.println(logMsg);
return returnValue;
}
}
This logs all calls to application classes with a name ending in 'Action'. It also adds the time each call took to complete. You might want to tweak the Around advice for a specific method name pattern as well. See the AspectJ programming guide
While it is perfectly "correct" to employ the strategy pattern as you have, but considering the fact that you're using Spring - it would be better to employ the Dependency Injection mechanism provided by the Spring framework - might as well put to use what your framework has to offer as one of its core strengths.
If each "dashboard" is has a controller, why not call the logging from the controller.
public interface DashboardLog
{
void createLog(...);
}
public class DashboardUno
implements DashboardLog
{
...
public void createLog(...)
{ ... }
}
#Controller
#RequestMapping("/blah/schmarr")
public class BlahController
{
...
#RequestMapping(value = "/xxx")
public String someMeaningfulName(...)
{
DashboardUno elEsUno;
... get the dashboard object ...
elEsUno.createLog(...);
...
}
}
I am developing RESTful API for my application. All getters (that use HTTP GET) work fine. I cannot make save method (that uses POST) to work.
I am using HTML form and RESTClient for testing.
Here is my Controller
#Controller
public class EntitiesController {
#RequestMapping(value="/ci/save/", method = RequestMethod.POST)
public ModelAndView saveConfigurationItem(#RequestBody ConfigurationItem body) {
System.out.println("saveConfigurationItem: body=" + body);
return createModelAndView("ci", Collections.emptyList());
}
}
This method is expected to be called when client posts ConfigurationItem.
I am using custom serialization format. It is not XML or JSON. It is VCard or VCalendar format. For my first test I used the following VCard:
BEGIN:VCARD
N:Pooh;Winnie
FN:Winnie the Pooh
TEL:tel:+441234567
END:VCARD
I posted it to URL http://localhost:8080/core.solution-1.0/data/ci/save/.
Here is the response I get:
415
The server refused this request because the request entity is in a format not
supported by the requested resource for the requested method ()
(*) ConfigurationItem is an abstract class. CardEntry extends it. I tried both.
I tried to change the method parameter to String. In this case the method is called but the string is empty. The same happens when following one of recommendations I saw in web I changed the parameter type to MultiValueMap and sent request from simple HTML form.
I saw that marshal() is not called at all.
What's wrong?
Here is what I have. (I put here relevant code only.)
Spring configuration
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:oxm="http://www.springframework.org/schema/oxm"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd">
<import resource="classes/spring-config-prod.xml"/>
<context:component-scan base-package="com.mycompany.solution.service" />
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver" />
<bean id="ciCardView" class="com.mycompany.solution.service.VFormatView">
<constructor-arg>
<bean class="com.mycompany.solution.service.VFormatMarshaller">
<property name="packagesToScan" value="com.mycompany.solution.entity"/>
</bean>
</constructor-arg>
</bean>
</beans>
Marshaller
public class VFormatMarshaller implements Marshaller, Unmarshaller {
#Override
public void marshal(Object obj, Result result)
throws IOException/*, XmlMappingException*/ {
System.out.println("VFormatMarshaller.marshal(" + obj + ")");
marshalStreamResult(obj, (StreamResult)result);
}
#Override
public boolean supports(Class<?> paramClass) {
System.out.println("VFormatMarshaller.supports(" + paramClass + ")");
boolean supports = new HashSet<String>(Arrays.asList(packagesToScan)).contains(paramClass.getPackage().getName());
if (supports) {
return supports;
}
return Collection.class.isAssignableFrom(paramClass);
}
#Override
public Object unmarshal(Source source) throws IOException/*, XmlMappingException*/ {
System.out.println("VFormatMarshaller.unmarshal(" + source + ")");
return unmarshalStreamSource((StreamSource)source);
}
//// .............................
}
View (this is written only to override the content type)
public class VFormatView extends MarshallingView {
public VFormatView() {
super();
setContentType("application/vcard");
System.out.println("VFormatView()");
}
public VFormatView(Marshaller marshaller) {
super(marshaller);
setContentType("application/vcard");
System.out.println("VFormatView(" + marshaller + ")");
}
}
#RequestBody/#ResponseBody are supported by an hierarchy of HttpMessageConverters, that is completely different from ViewResolvers.
In you case you need to configure a MarshallingHttpMessageConverter with appropriate marshaller/unmarshaller and content type (or create your own HttpMessageConverter if you don't need to depend on the existing implementation of marshaller/unmarshaller), and supply a configured instance to AnnotationMethodHandlerAdapter.
The least intrusive way to configure a custom HttpMessageConveter is to create a BeanPostProcessor as follows:
public class Configurer implements BeanPostProcessor {
public void postProcessAfterInitialization(String name, Object bean) {
if (bean instanceof AnnotationMethodHandlerAdapter) {
AnnotationMethodHandlerAdapter a = (AnnotationMethodHandlerAdapter) bean;
HttpMessageConverter[] convs = a.getMessageConverters();
... add new converter ...
a.setMessageConverters(convs);
}
}
...
}