How do I use spring property sources within a child annotation context? - java

I'm trying to replicate something that works with XML config using annotated configuration classes. The problem I'm hitting is that property sources defined in the child context are not accessible.
The xml that works looks like
Parent context :
<?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.xsd">
<bean id="proxyChannelQueue" class="java.util.concurrent.ArrayBlockingQueue">
<constructor-arg value="10"/>
</bean>
</beans>
Child Context :
<?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:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder location="proxy-host.properties"/>
<bean class="org.eclipse.jetty.server.Server"
p:handler-ref="proxyHostHandler"
init-method="start">
<constructor-arg value="${proxyHostPort}"/>
</bean>
<bean id="proxyHostHandler" class="com.sjl.web.ProxyHostHandler"
p:proxyChannelQueue-ref="proxyChannelQueue"/>
</beans>
Start up code :
ClassPathXmlApplicationContext parentContext = new ClassPathXmlApplicationContext("test/parent-context.xml");
ClassPathXmlApplicationContext childContext = new ClassPathXmlApplicationContext(new String[] {"test/child-context.xml"}, parentContext);
My attempt at doing this using configuration classes looks like.
Parent Context :
#Configuration
public class ParentConfiguration {
#Bean(name = "proxyChannelQueue")
public BlockingQueue<ProxyChannel> getProxyChannelQueue() {
return new ArrayBlockingQueue<ProxyChannel>(10);
}
}
Child Context :
#Configuration
#PropertySource("classpath:proxy-host.properties")
public class ChildContext {
private static final Logger LOGGER = LoggerFactory.getLogger(ChildContext.class);
#Autowired
private Environment environment;
#Resource(name = "proxyChannelQueue")
private BlockingQueue<ProxyChannel> proxyChannelQueue;
public static void main(String[] args) {
new HierarchicalAnnotationConfigApplicationContext(ChildContext.class);
}
#Bean
public Server getJettyServer() throws Exception {
int proxyHostPort = environment.getProperty("proxyHostPort", Integer.class);
Server server = new Server(proxyHostPort);
server.setHandler(getHandler());
server.start();
return server;
}
#Bean
public Handler getHandler() {
ProxyHostHandler proxyHostHandler = new ProxyHostHandler();
proxyHostHandler.setProxyChannelQueue(proxyChannelQueue);
return proxyHostHandler;
}
}
Start up code :
AnnotationConfigApplicationContext parentContext = new AnnotationConfigApplicationContext(ParentConfiguration.class);
AnnotationConfigApplicationContext childContext = new AnnotationConfigApplicationContext();
childContext.setParent(parentContext);
childContext.register(ChildContext.class);
childContext.refresh();
I'm getting a null pointer while trying to retrieve the proxyHostPort within the ChildContext getJettyServer method. Inspecting the environment variable shows that it contains only 2 property sources (systemProperties and systemEnvironment) and not the 3 I expect.
The same configuration works if I run them as a single combined context. E.g. :
AnnotationConfigApplicationContext parentContext = new AnnotationConfigApplicationContext(ParentConfiguration.class, ChildContext.class);
However I want the isolation that using parent contexts provide.
Cheers,
Peter

Related

CannotLoadBeanClassException when try to get a bean from applicationContext.xml

i have just started a course about Spring framework and i am struggling getting over this exceiption:
Exception in thread "main" org.springframework.beans.factory.CannotLoadBeanClassException: Cannot find class [TrackCoach] for bean with name 'myCoach' defined in class path resource [applicationContext.xml]; nested exception is java.lang.ClassNotFoundException: TrackCoach
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1476)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineTargetType(AbstractAutowireCapableBeanFactory.java:682)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:649)
at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1604)
at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1080)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:859)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:878)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:144)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:85)
at com.love2code.springdemo.HelloSpringApp.main(HelloSpringApp.java:9)
This is my main class:
package com.love2code.springdemo;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class HelloSpringApp {
public static void main(String[] args) {
//load the spring configuration file
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//retrieve bean from spring container
Coach theCoach = context.getBean("myCoach", Coach.class);
//call methods on the bean
System.out.println(theCoach.getDailyWorkout());
//close the context
context.close();
}
}
My TrackCoach class:
package com.love2code.springdemo;
public class TrackCoach implements Coach {
#Override
public String getDailyWorkout() {
return "Smoke 2 bl's";
}
}
And applicationContext.xml:
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- Define your beans here -->
<bean id="myCoach" class="com.luv2code.springdemo.TrackCoach">
</bean>
</beans>
Could someone help me out with this please?

SpringBoot define custome annotation include #Configuration #ImportResource

I'm try to define a custome annotation include #Configuration and #ImportResource
but #ImportResource doesn't work
Any suggestions?
#Documented
#Configuration
#ImportResource
#Target({ElementType.TYPE})
#Order(Ordered.HIGHEST_PRECEDENCE)
#Retention(RetentionPolicy.RUNTIME)
public #interface EnableXXConfiguration {
#AliasFor(annotation = ImportResource.class , attribute = "value")
String[] value() default {};
}
#ImportResource contains two attributes value and locations. The value attribute is ultimately alias for locations attribute so using either of the aliases works fine. Keeping your Custom annotation(EnableXXConfiguration) declaration (the one using value attribute) as it, use below code snippet.
#EnableXXConfiguration(value = { "context1.xml", "com/example/stackoverflow/context2.xml"})
public class DemoApp {
#Autowired
private BeanA beanA;
#Autowired
private BeanB beanB;
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DemoApp.class);
DemoApp demoAppObj = (DemoApp) context.getBean("demoApp");
System.out.println("BeanA member: " + demoAppObj.getBeanA());
System.out.println("BeanB member: " + demoAppObj.getBeanB());
}
public BeanA getBeanA() {
return beanA;
}
public BeanB getBeanB() {
return beanB;
}
}
Assume we are using two xmlss placed at two different locations. context1.xml is placed in resource folder(src/main/resource) and context2.xml is placed at any other location (here at: src/main/java/com/example/stackoverflow)
context1.xml
<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.xsd">
<bean id="beanA" class="com.example.stackoverflow.BeanA" />
</beans>
context2.xml
<?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.xsd">
<bean id="beanB" class="com.example.stackoverflow.BeanB" />
</beans>

Spring does not load LDAP-XML config file

I have a prototype spring application to play with spring-security and LDAP. The application works with the internal LDAP-Server. But when I want to define an individual connection with a xml-config it doesn't work. More specific: The LdapTemplate which should be instantiated by the xml-config stays a null-object. Here is the code:
public class UserRepo {
#Autowired
private LdapTemplate ldapTemplate; //stays null
public static final String BASE_DN = "dc=springframework,dc=org";
//this works, but is not desired:
public UserRepo() {
// final GenericXmlApplicationContext appContext = new GenericXmlApplicationContext("classpath:ldap.xml");
// appContext.refresh();
// ldapTemplate = (LdapTemplate)appContext.getBean(LdapTemplate.class);
// LdapContextSource lcs = new LdapContextSource();
// lcs.setUrl("ldap://127.0.0.1:389/");
// lcs.setUserDn(BASE_DN);
// lcs.setDirObjectFactory(DefaultDirObjectFactory.class);
// lcs.setAnonymousReadOnly(true);
// lcs.afterPropertiesSet();
// ldapTemplate = new LdapTemplate(lcs);
}
My config looks 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:ldap="http://www.springframework.org/schema/ldap"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/ldap http://www.springframework.org/schema/ldap/spring-ldap.xsd">
<ldap:context-source
id="contextSource"
url="ldap://localhost:389"
base="dc=example,dc=com"
username="cn=Manager"
password="secret" />
<ldap:ldap-template id="ldapTemplate" />
<bean id="userRepo" class="user.UserRepo">
<property name="ldapTemplate" ref="ldapTemplate" />
</bean>
</beans>
I have put the ldap.xml one time in the src-dir and another time in the ressource-dir, both didn't work.
I hope you can tell me what I'm doing wrong.
Add a #Component annotation to your UserRepo class and a proper annotation-config (or component-scan element if required). Since your commented-out code works, the LdapTemplate bean is created succesfully, and injected because you use a GenericXmlApplicationContext. To test it with annotations you need an AnnotationConfigApplicationContext instead.

java.lang.NullPointerException at object instantiation

My application uses struts and spring frameworks. I have a class FormA which has an autowired property in it. When I try to instantiate it while writing unit tests I get a Null Pointer Exception. Here is my code.
My ClassA:
public class FormA{
private String propertyOne;
#Autowired
private ServiceClass service;
public FormA(){
}
}
My unit test method:
#Test
public void testFormA(){
FormA classObj = new FormA();
}
#Autowired only works when object life cycle is managed by Spring.
You'll need to run your tests with #RunWith(SpringJUnit4ClassRunner.class), and instead of instantiating FormA manually, inject it in the test class as well, using #Autowired.
When you create an object by new, autowire\inject don't work...
as workaround you can try this:
create your template bean of NotesPanel
<bean id="notesPanel" class="..." scope="prototype">
<!-- collaborators and configuration for this bean go here -->
</bean>
and create an istance in this way
applicationContext.getBean("notesPanel");
PROTOTYPE : This scopes a single bean definition to have any number of object instances.
anyway a unit test should be
Test class
#RunWith( SpringJUnit4ClassRunner.class )
#ContextConfiguration(locations = { "classpath:META-INF/your-spring-context.xml" })
public class UserServiceTest extends AbstractJUnit4SpringContextTests {
#Autowired
private UserService userService;
#Test
public void testName() throws Exception {
List<UserEntity> userEntities = userService.getAllUsers();
Assert.assertNotNull(userEntities);
}
}
your-spring-context.xml
<?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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<bean id="userService" class="java.package.UserServiceImpl"/>
</beans>

#Value annotation from Spring3 doesn't work in my program

I'm writing a java application with Spring 3.It's working well with xml,but not working at all in annotation.
here's my snippet:
#Service("oracleDB")
public class OracleDatabase implements IDatabase
{
#Value("oracle.jdbc.driver.OracleDriver")
private String driverName;
#Value("jdbc:oracle:thin:#")
private String url;
public String getDriverName()
{
return driverName;
}
}
My ApplicationContext.xml is 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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config />
<context:component-scan
base-package="com.pdiwt.database"></context:component-scan>
</beans>
MyInvoker is like that:
public class MyInvoker{
public static void main(String args[]){
XmlBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
OracleDatabase oracelDB = beanFactory.getBean("oracleDB");
System.out.println(oracleDB.getDriverName());
}
}
guess what? The result is null. Is there anything wrong?
The problem here is using xmlbeanfactory, which is a common mistake. Try this instead, it will work perfectly:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
OracleDatabase oracleDB = (OracleDatabase)context.getBean("oracleDB");
...
I think the beanfactory is simply not powerful enough to handle the #Value annotations. More information can be found here.
If you're already using Spring, why would you get a connection this way instead of using Spring's DataSources? Seems odd at best; wrong-headed at worst.
I'd be giving that Repository a JdbcTemplate.

Categories