I stuck converting my current test app in Spring from using XML configuration to using Java configuration...
I have the following files
App.java
package com.spring.ioc.DependencyInjection;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("app-config.xml");
Phone p = ctx.getBean("phone", Phone.class);
p.calling();
p.data();
}
}
Galaxy.java
package com.spring.ioc.DependencyInjection;
public class Galaxy implements Phone {
public void calling() {
System.out.println("Calling using Galaxy");
}
public void data() {
System.out.println("Browsing internet using Galaxy");
}
}
IPhone.java
package com.spring.ioc.DependencyInjection;
public class IPhone implements Phone {
public void calling() {
System.out.println("Calling using iPhone");
}
public void data() {
System.out.println("Browsing internet using iPhone");
}
}
Phone.java
package com.spring.ioc.DependencyInjection;
public interface Phone {
void calling();
void data();
}
app-config.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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="phone" class="com.spring.ioc.DependencyInjection.IPhone"></bean>
</beans>
The code above allows me to demo how you can use XML & edit the text between 'IPhone' or 'Galaxy' by changing the bean name at the end of the fully qualified name
<bean id="phone" class="com.spring.ioc.DependencyInjection.IPhone"></bean>
or
<bean id="phone" class="com.spring.ioc.DependencyInjection.Galaxy"></bean>
How can do the same in using JavaConfig instead of XML config?
I know how to use Java configuration to just pull one bean but am lost how to set it up to alternate between two objects.
Can you please show me by modifying the code I provided or adding any other code needed?
I believe you can use
#Component("iphone")
public class IPhone {}
#Component("galaxy ")
public class Galaxy {}
and where you inject it,
#Autowired
#Qualifier(value = "iphone")
private Phone iPhone;
#Autowired
#Qualifier(value = "galaxy")
private Phone galaxy;
Related
I am trying to use the properties file and inject it to my fields of a class, but I am getting null .
I have created a properties file called fortune.properties:
fortune1=Have a good day
fortune2=Have a bad day
fortune3=Have a medioccure day
Then I am loading it in the applicationContext.xml 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"
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">
<!-- Enable Component Scanning -->
<context:component-scan base-package="com.luv2code.springdemo"></context:component-scan>
<context:property-placeholder location="classpath:fortune.properties" />
</beans>
In the RandomFortuneClass, I am using value injection using #Value() annotation:
package com.luv2code.springdemo;
import java.util.Random;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
#Component()
public class RandomFortuneService implements FortuneService {
#Value("${fortune1}")
private String fortune1;
#Value("${fortune2}")
private String fortune2;
#Value("${fortune3}")
private String fortune3;
String[] fortunes = new String[] {fortune1, fortune2, fortune3};
private Random random = new Random();
#Override
public String getFortune() {
int index = random.nextInt(fortunes.length);
return fortunes[index];
}
}
Then I am declaring fortuneService in SwimCoach class using constructor injection:
package com.luv2code.springdemo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
#Component()
public class SwimCoach implements Coach {
private FortuneService fortuneService;
#Autowired
SwimCoach(#Qualifier("randomFortuneService") FortuneService fs) {
fortuneService = fs;
}
#Override
public String getDailyWorkout() {
System.out.println();
return "Swim 5m everyday";
}
#Override
public String getDailyFortune() {
return fortuneService.getFortune();
}
}
Now when I try to call the method getDailyFortune in the AnnotationDemoApp class, I always get null as output.
package com.luv2code.springdemo;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AnnotationDemoApp {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Coach theCoach = context.getBean("swimCoach", Coach.class);
System.out.println(theCoach.getDailyFortune());
context.close();
}
}
What is the error here?
Kindly comment if more information is needed.
Here is my file hierarchy:
PS: I am following the spring & hibernate course for beginners by Chad Darby.
You simply need to move fortune.properties into /src/main/resources, but let me suggest a cleaner way...
First, drop the xml configuration, it's outdated by several years and everything you can do there can be done via java annotations.
Second, add your property files to src/main/resources.
Third, tell Spring where to resolve your properties from, you can do this by adding #PropertySources({#PropertySource("fortune.properties")}) to a configuration class like this (also note that I've added the #ComponentScan and #Configuration annotations here):
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.PropertySource;
#Configuration
#ComponentScan
#PropertySource("fortune.properties")
public class Config {
}
Fourth, in your main method, use the AnnotationConfigApplicationContext as opposed to the ClassPathXmlApplicationContext. I think you'll find it's much cleaner.
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
Coach theCoach = context.getBean("swimCoach", Coach.class);
System.out.println(theCoach.getDailyFortune());
}
I want to test a class that simple shutdown the application:
#Component
public class ShutdownManager {
#Autowired
private ApplicationContext applicationcontext;
public int shutdown(int returnCode) {
return SpringApplication.exit(applicationcontext, () -> returnCode);
}
}
The test case I created is this:
public class ShutdownManagerTest {
#Test
public void should_shutdown_gracefully() {
SpringApplication app = new SpringApplication(TestClass.class);
ConfigurableApplicationContext context = app.run();
ShutdownManager shutdownManager = (ShutdownManager)context.getBean("shutdownManager");
int result = shutdownManager.shutdown(10);
assertThat(result).isEqualTo(10);
}
#SpringBootApplication
#ImportResource("classpath:/core/shutdownmanagertest.xml")
private static class TestClass {
public TestClass() {
}
public static void main(String[] args) {
}
}
}
My shutdownmanagertest.xml contains only one bean:
<?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="shutdownManager" class="com.mycodebase.ShutdownManager" />
</beans>
However, when I run this, it complains that:
Field myOtherService in com.mycodebase.MyTask required a bean of type 'com.mycodebase.MyOtherService ' that could not be found.
The class MyTask is in the same package of the ShutdownManager which contains a field myOtherService which has an #Autowire annocation. But it is not defined in my test xml which contains just one bean.
Can someone help me understand why it tries to resolve a bean that is not in the context?
It's doing that because that's how #SpringBootApplication works.
#SpringBootApplication:
This is a convenience annotation that is equivalent to declaring #Configuration, #EnableAutoConfiguration and #ComponentScan.
#ComponentScan
If specific packages are not defined, scanning will occur from the package of the class that declares this annotation.
So everything in the same or a subpackage of ShutdownManagerTest is being picked up.
I am learning Spring and was trying to implement the following code from the book "Spring in Action". I am not able to understand as to why the Interface property declared with exact name works and else doesn't for a simple Spring application(3.0). Please look into this:
public interface Instrument {
public void play();
}
public interface Performer
{
void perform();
}
public class Saxophone implements Instrument
{
public void play() {
System.out.println("TOOT TOOT TOOT");
}
}
public class Instrumentalist implements Performer
{
private String song;
private Instrument obj; *// not working
// private Instrument instrument; This will work, if replaced* accordingly in the code
public void setSong(String song)
{
this.song=song;
}
public void setInstrument(Instrument instrumen)
{
obj=instrumen;
}
public Instrument getInstrument()
{
return obj;
}
public String getSong()
{
return song;
}
public void perform(){
System.out.println("Playing "+song+" : ");
obj.play();
}
}
The Main class is :
import org.springframework.context.*;
import org.springframework.context.support.*;
class Main
{
public static void main(String ar[])
{
ApplicationContext ctx = new ClassPathXmlApplicationContext("abc.xml");
Performer performer = (Performer) ctx.getBean("kenny");
performer.perform();
}
}
And the configuration are:
<?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-3.0.xsd"
default-init-method="turnONLights" default-destroy-method="turnOFFLights">
<bean id="kenny" class="Instrumentalist">
<property name="song" value="Jingle Bells" />
<property name="obj" ref="saxophone" />
<!-- here also I need to replace obj with "instrument" to make it work -->
</bean>
<bean id="saxophone" class="Saxophone"/>
</beans>
This might be a basic question but yet I am not able to get it.Please help me understand that is it necessary to have the Interface variable have the same name?
Many Thanks
This part looks incorrect...
<property name="obj" ref="saxophone" />
The value of the name attribute needs to be derived from the setter method; in this case, it looks like you want...
<property name="instrument" ref="saxophone" />
Notice that the characters s-e-t are removed, and the first character -- 'i' -- is lower case.
I am very new to SO,I have working on the task where Load environment configurations and properties according to the environment like (dev,prod,test),I have been successfully achieved database configuration on DAO level by using <beans profile="profile.name">. In front end side I have to get properties file according to the environment so I have the different files. to call that i have tried the below code:
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
#Component
public class PropertiesUtility {
#Value("${mount.images.webpath}")
private String imagePath;
public String getImagePath() {
return imagePath;
}
public void setImagePath(String imagePath) {
this.imagePath = imagePath;
}
#Override
public String toString() {
return "PropertiesUtility{" +
"imagePath='" + imagePath + '\'' +
'}';
}
}
My context.xml configuration:
<context:annotation-config/>
<beans profile="dev">
<context:property-placeholder location="classpath:properties/pharmisa_web_conf.properties"
ignore-unresolvable="true" />
</beans>
<beans profile="test">
<context:property-placeholder location="classpath:properties/pharmisa_web_test_conf.properties"
ignore-unresolvable="true" />
</beans>
Calling PropertiesUtility:
public class URLUtility {
#SpringBean //even #Autowired also not working
static PropertiesUtility propertiesUtility;
public static String getCompanyLogoUrl(int id) {
StringBuffer sb = new StringBuffer(getImagePath());
boolean isEndWithSlash=PharmisaStringUtils.endsWith(getImagePath(),"/");
if (!isEndWithSlash){
sb.append("/");
}
sb.append(id);
sb.append("/");
return sb.toString();
}
private static final String getImagePath() {
return propertiesUtility.getImagePath().trim();
}
}
SpringJunitTest
Test working perfectly
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:spring/pharmisa_web-context.xml"})
#ActiveProfiles(profiles = "test")
public class CompanyServiceImplTest {
#Autowired
PropertiesUtility propertiUtility;
#Test
public void testAppProperties() {
System.out.println(propertiUtility.getImagePath());
}
}
When i tried to inject PropertiesUtility class in wicket page .I am not getting the value of the properties. because it is not injected. I have aware of #SpringBean in wicket but even though it is not working.
Is there anyway to get the value any alternative welcomes.
For your further i have followed the link
http://examples.javacodegeeks.com/enterprise-java/spring/load-environment-configurations-and-properties-with-spring-example/
URLUtility should be a Spring bean if you want #Component or #Autowire to work.
#SrpingBean works automatically only in Wicket components. In anything else you need to "ask for injection" explicitly with Injector.get().inject(this).
This question already has answers here:
Using Spring 3 autowire in a standalone Java application
(5 answers)
Closed 9 years ago.
Is there a way to run Spring application configured by annotation, directly from main method?
I'm still getting NullPointerException runing code below. Note that I'm not using SpringMVC and when I'm using beans defined inside context.xml, injected inside main method by context.getBean method, all code works perfect (without error) - but I just wondering if it is a way to manage runing this only with annotations?
//IElem.java
package com.pack.elem;
public interface IElem {
public abstract String sayHello();
}
//Elem.java
package com.pack.elem;
import org.springframework.stereotype.Component;
#Component
public class Elem implements IElem{
#Override
public String sayHello() {
return ("Hello from Elem class object");
}
}
//RunElem.java
package com.pack.elem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class RunElem {
#Autowired
private IElem elem;
public void runHello(){
System.out.println(elem.sayHello());
}
}
//Main.java
package com.pack.main;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.pack.elem.RunElem;
public class Main {
#Autowired
private RunElem runelem;
public static void main(String[] args) {
ApplicationContext context= new ClassPathXmlApplicationContext("/META-INF/application-context.xml");
new Main().runRun();
}
private void runRun(){
runelem.runHello();
}
}
<!--/META-INF/application-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: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-3.2.xsd">
<context:annotation-config/>
<context:component-scan base-package="com.pack"/>
</beans>
Put simply, Spring is autowiring if it is the one instantiating the bean. So you have to use getBean(). If you want to use annotations only, something like this should work:
#Component
public class Main {
#Autowired
private RunElem runelem;
public static void main(String[] args) {
ApplicationContext context= new ClassPathXmlApplicationContext("/META-INF/application-context.xml");
Main mainBean = context.getBean(Main.class);
mainBean.runRun();
}
private void runRun(){
runelem.runHello();
}
}
Alternatively you can autowire an existing bean as shown below, but this is not a recommended Spring usage:
public class Main {
#Autowired
private RunElem runelem;
public static void main(String[] args) {
ApplicationContext context= new ClassPathXmlApplicationContext("/META-INF/application-context.xml");
Main mainBean = new Main();
context.getAutowireCapableBeanFactory().autowireBean(mainBean);
mainBean.runRun();
}
private void runRun(){
runelem.runHello();
}
}