Spring config didn't work as expected - java

I'm building a new project, and I thought I'd try a new way of loading my Spring config. I found the #Configuration annotation and decided to give it a try.
#Configuration
#ImportResource("classpath:myApp-config.xml")
public class MyAppConfig
{
#Autowired
private MyClass myClass;
#Bean(name="someOtherBeanName")
public MyClass getMyClass ()
{
return myClass;
}
public void setMyClass( myClass m)
{
this.myClass= m;
}
}
In the spring config file:
<context:annotation-config/>
<bean name="someOtherBeanName" class="com.MyClass">
<property name="myClass">
<map>
<!-- details not relevant -->
</map>
</property>
</bean>
To make use of this, I have code like this:
//class member
private static MyAppConfig cfg = new MyAppConfig();
...
...
...
//In the class that needs the configuration
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(MyAppConfig.class);
ctx.refresh();
//appMgr = cfg.getMyClass();
appMgr = (MyClass) ctx.getBean("someOtherBeanName");
As you can see, I'd thought I could get a spring-configured instances of MyClass from my configuration object, but instead I had to get it from my context object.
I guess I misunderstood the way #Configuration and #Bean work. Am I pretty close or way off?

You cannot get your bean from cfg.getMyClass();, there are some misunderstanding.
#Configuration is only another representation of spring configuration, you should understand it just like your application-context.xml, nothing is new here.

This
private static MyAppConfig cfg = new MyAppConfig();
is not a Spring managed bean so you will get null when calling getMyClass().
Also, the following
#ImportResource("classpath:myApp-config.xml")
with
#Autowired
private MyClass myClass;
#Bean(name="someOtherBeanName")
public MyClass getMyClass ()
{
return myClass;
}
is redundant. Because of the #ImportResource, the bean from the XML configuration is already in the context.
Indicates one or more resources containing bean definitions to import.
You don't need an additional #Bean method in between.

You are pretty way off... going full Java-based config will be for your example:
#Configuration
public class MyAppConfig {
#Bean
public MyClass someOtherBeanName() {
MyClass myClass = new MyClass();
myClass.setMyProp(null /* details not relevant */);
return myClass;
}
}
Somewhere else in the main method (this is unchanged):
//In the class that needs the configuration
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(MyAppConfig.class);
ctx.refresh();
//appMgr = cfg.getMyClass();
appMgr = (MyClass) ctx.getBean("someOtherBeanName");

Add something that you might meet, if u still can not find config.xml or javaconfig.class. Check your file structure.
src
config.xml or javaconfig.java
To save your config in your path(default package is src)

Related

Injecting library class as dependencies in spring project

I have multiple library classes in my project which need to be injected into a service class. This is the error statement for IntegrationFactory class:
Consider defining a bean of type 'com.ignitionone.service.programmanager.integration.IntegrationFactory' in your configuration.
This error is coming on almost every injection where this library class is injected.
I have already added the Library package in #ComponentScan, but, as it is read-only file, I can not annotate the library class. I came to know from some answer here that Spring can not inject classes which it does not manage. This library is not built on spring.
I have tried to create a #Bean method which returns the IntegrationFactory(class in question) in the class where #Inject is used, but this too does not seem to work.
How can this be done, preferably without creating a stub/copy class?
This is EngagementServiceImpl class snippet:
#Inject
public EngagementServiceImpl(EngagementRepository engagementRepository,
#Lazy IntegrationFactory integrationFactory, TokenRepository tokenRepository,
EngagementPartnerRepository engagementPartnerRepository, MetricsService metricsService) {
this.engagementRepository = engagementRepository;
this.integrationFactory = integrationFactory;
this.tokenRepository = tokenRepository;
this.engagementPartnerRepository = engagementPartnerRepository;
this.metricsService = metricsService;
}
This is injection part:
#Autowired
private EngagementService engagementService;
This is ConfigClass:
#Configuration
public class ConfigClass {
#Bean
public IntegrationFactory getIntegrationFactory(){
Map<String, Object> globalConfig = new HashMap<>();
return new IntegrationFactory(globalConfig);
}
#Bean
#Primary
public EntityDataStore getEntityDataStore(){
EntityModel entityModel = Models.ENTITY;
return new EntityDataStore(this.dataSource(), entityModel );
}
#ConfigurationProperties(prefix = "datasource.postgres")
#Bean
#Primary
public DataSource dataSource() {
return DataSourceBuilder
.create()
.build();
}
}
You need to add your bean definitions in a configuration class.
#Configuration
public class ServiceConfig {
#Bean
public IntegrationFactory getIntegrationFactory(){
// return an IntegrationFactory instance
}
}
Then you have to make sure your #Configuration class gets detected by Spring, either by having it within your scanned path or by manually importing it via #Import from somewhere withing you scanned path. An example of #Import, considering you are using Spring Boot.
#Import(ServiceConfig.class)
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Hope this helps!
Your Bean IntegrationFactory can't be found, as it is not annotated with any Spring stereotype and therefore not recognized by the component scan.
As you have multiple options to provide an instance of your class to the application context, read the Spring documentation (which also includes samples) to find out which one fits you the most:
https://docs.spring.io/spring/docs/5.1.0.RELEASE/spring-framework-reference/core.html#beans-java-basic-concepts
One Option would be to create a factory which provides an instance of your class to the application context, like it is stated in the documentation:
#Configuration
public class AppConfig {
#Bean
public IntegrationFactory myIntegrationFactory() {
return new IntegrationFactory();
}
}
Do not forget to add the Configuration to the application context.

Autowired Class is returning null values

I'm implemented a little service based on Spring. I would like to autowire the class Demo within the DemoController. Therefore I defined the values for it within the beans.xml file. It seems like spring finds the bean because everything is compiling. But the return value of the service looks like this:
{"valueUno":0,"valueDue":null}
DemoApplication:
#SpringBootApplication
#ComponentScan({"com"})
#EnableAutoConfiguration
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
Demo:
#Component
public class Demo {
private int valueUno;
private String valueDue;
//getter, setter....
}
DemoController:
#RestController
public class DemoController {
#Autowired
private Demo demo;
#RequestMapping(
value = "/welcome",
method = RequestMethod.GET
)
public HttpEntity<Demo> getMessage() {
return new HttpEntity<Demo>(this.demo);
}
}
beans.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="demo" class="com.example.demo.Demo">
<property name="valueUno" value="50"></property>
<property name="valueDue" value="Hello"></property>
</bean>
</beans>
Everything is inside one package. I dont get it...
You have annotated Demo as a #Component. Therefore, Spring instantiates a bean of this class using its default constructor during the component scan (you have enabled it with #ComponentScan({"com"})), and then injects (autowires) it into DemoController. So, the autowired bean not the one defined in beans.xml.
There are 2 ways to solve the issue:
1) If you want to go with XML configuration, remove #Component from Demo class, and add #ImportResource("classpath:beans.xml") annotation to your Controller class.
2) If you want to go with JavaConfig (annotations), you would need to add separate class like this:
#Configuration
public class MyConfiguration {
#Bean
public Demo demo() {
return new Demo(50, "Hello"); // or initialize using setters
}
}
...and add #Import(MyConfiguration.class) annotation to your Controller class, and remove #Component from Demo class.
As a solution to what #PresentProgrammer said, you can move your XML configuration to a Java configuration as following:
#Bean
public Demo demo() {
Demo demo = new Demo();
demo.setValueUno(50);
demo.setValueDue("Hello");
return demo;
}
You can add this configuration directly to the DemoApplication class or to a configuration class:
#Configuration
public class BeanConfiguration {
//Bean Configurations
}
For further details, you can read Java-based container configuration Spring documentation.

Spring annotations confusion

i am really confused with spring annotations.
where to use # Autowired, where class is # Bean or # Component,
i understand we cannot use
Example example=new Example("String");
in Spring
but how alone
#Autowired
Example example;
will solve the purpose?
what about Example Constructor ,how spring will provide String value to Example Constructor?
i went through one of the article but it does not make much sense to me.
it would be great if some one can give me just brief and simple explanation.
Spring doesn't say you can't do Example example = new Example("String"); That is still perfectly legal if Example does not need to be a singleton bean. Where #Autowired and #Bean come into play is when you want to instantiate a class as a singleton. In Spring, any bean you annotate with #Service, #Component or #Repository would get automatically registered as a singleton bean as long as your component scanning is setup correctly. The option of using #Bean allows you to define these singletons without annotating the classes explicitly. Instead you would create a class, annotate it with #Configuration and within that class, define one or more #Bean definitions.
So instead of
#Component
public class MyService {
public MyService() {}
}
You could have
public class MyService {
public MyService() {}
}
#Configuration
public class Application {
#Bean
public MyService myService() {
return new MyService();
}
#Autowired
#Bean
public MyOtherService myOtherService(MyService myService) {
return new MyOtherService();
}
}
The trade-off is having your beans defined in one place vs annotating individual classes. I typically use both depending on what I need.
You will first define a bean of type example:
<beans>
<bean name="example" class="Example">
<constructor-arg value="String">
</bean>
</beans>
or in Java code as:
#Bean
public Example example() {
return new Example("String");
}
Now when you use #Autowired the spring container will inject the bean created above into the parent bean.
Default constructor + #Component - Annotation is enough to get #Autowired work:
#Component
public class Example {
public Example(){
this.str = "string";
}
}
You should never instantiate a concrete implementation via #Bean declaration. Always do something like this:
public interface MyApiInterface{
void doSomeOperation();
}
#Component
public class MyApiV1 implements MyApiInterface {
public void doSomeOperation() {...}
}
And now you can use it in your code:
#Autowired
private MyApiInterface _api; // spring will AUTOmaticaly find the implementation

Replacing Spring bean injection via XML with annotation injection

I want to declare and inject a bean through annotations. It was previously done through XML, but I need to apply on a Spring Boot project.
Here is the source xml
<oauth:resource-details-service id="rds">
<oauth:resource
id="oauth1"
key="${key}"
secret="${secret}"
request-token-url="${token}"
user-authorization-url="${user-auth}"
access-token-url="${accesstokenurl}">
</oauth:resource>
</oauth:resource-details-service>
The bean was later used like this
<bean class="org.springframework.security.oauth.consumer.client.OAuthRestTemplate">
<constructor-arg ref="oauth1"/>
</bean>
The only way I found is through direct instantiation
BaseProtectedResourceDetails resourceDetails = new BaseProtectedResourceDetails();
resourceDetails.set...
resourceDetails.set...
OAuthRestTemplate restTemplate = new OAuthRestTemplate(resourceDetails);
What would be the proper way to do this?
you can use #Bean annotation in your main class for example:
#SpringBootApplication
public class Application{
#Bean
public OAuthRestTemplate getAuth(){
BaseProtectedResourceDetails resourceDetails = new BaseProtectedResourceDetails();
resourceDetails.set...
resourceDetails.set...
return new OAuthRestTemplate(resourceDetails);
}
}
and after use #Autowired to inject the object
#Autowired
private OAuthRestTemplate oAuthRestTemplate;
I am not sure you are searching for this explanation. But if I understand you question then following information may help you.
For Sample configuration class you can see this example.
package com.tutorialspoint;
import org.springframework.context.annotation.*;
#Configuration
public class TextEditorConfig {
#Bean
public TextEditor textEditor(){
return new TextEditor( spellChecker() );
}
#Bean
public SpellChecker spellChecker(){
return new SpellChecker( );
}
}
And for registering configuration class, you can see this SO answer.
See this for #Service, #Component, #Repository, #Controller, #Autowired related example.

How to AutoWire an object without Spring XML context file?

I have an Interface with Component annotation and some classes that implemented it as follows:
#Component
public interface A {
}
public class B implements A {
}
public class C implements A {
}
Also, I have a class with an Autowired variable like this:
public class Collector {
#Autowired
private Collection<A> objects;
public Collection<A> getObjects() {
return objects;
}
}
My context file consists of these definitions:
<context:component-scan base-package="org.iust.ce.me"></context:component-scan>
<bean id="objectCollector" class="org.iust.ce.me.Collector" autowire="byType"/>
<bean id="b" class="org.iust.ce.me.B"></bean>
<bean id="c" class="org.iust.ce.me.C"></bean>
And in the main class, I have some codes as follows:
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
B b = (B) context.getBean("b");
C c = (C) context.getBean("c");
Collector objectCollector = (Collector) context.getBean("objectCollector");
for (A object : objectCollector.getObjects()) {
System.out.println(object);
}
Output:
org.iust.ce.me.B#1142196
org.iust.ce.me.C#a9255c
These codes work well, but for some reasons I’m not willing to use xml context file. Besides it, I prefer to create the objects with the new operator rather than using the getBean() method. Nevertheless, since the AutoWiring is really good idea in programming, I don’t want to lose it.
Now I have two questions!!
how can I AutoWire classes that implements the A Interface without using the xml context file?
Is it possible at all?
when I change the scope of a bean from singlton to
prototype as follows:
<bean id="b" class="org.iust.ce.me.B" scope="prototype"></bean>
and instantiate several beans of it, only the bean which was instantiated during creating context, is injected into AutoWired variable. Why?
Any help will be appreciated.
Not sure the version of Spring you are using. But currently you can use #Configuration to replace .xml. Take a look at #Configuration
Below is the code in documentation
#Configuration
public class ServiceConfig {
private #Autowired RepositoryConfig repositoryConfig;
public #Bean TransferService transferService() {
return new TransferServiceImpl(repositoryConfig.accountRepository());
}
}
#Configuration
public interface RepositoryConfig {
#Bean AccountRepository accountRepository();
}
#Configuration
public class DefaultRepositoryConfig implements RepositoryConfig {
public #Bean AccountRepository accountRepository() {
return new JdbcAccountRepository(...);
}
}
#Configuration
#Import({ServiceConfig.class, DefaultRepositoryConfig.class}) // import the concrete config!
public class SystemTestConfig {
public #Bean DataSource dataSource() { /* return DataSource */ }
}
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);
TransferService transferService = ctx.getBean(TransferService.class);
transferService.transfer(100.00, "A123", "C456");
}
Provided the classes to be managed have been correctly annotated, Spring can scan the application's files to get the information it needs without any xml or java configuration files at all.
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.scan("com.something.something.etc");
context.refresh();
...context.getBean("name_of_bean");
Note AnnotationConfigApplicationContext is instantiated without any arguments. context.scan("..."); takes a string that tells Spring where to look. i.e. packagescom.something.something.etc.one
com.comething.something.etc.twowill be scanned, and classes within those packages annotated with #Component, #Autowired, etc. will be instatiated and injected where needed.
This approach doesn't seem to be as well documented.
1- You need to write another class that will do the operation. write #Component to B and C class.
public static void main(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
InitClass initClass = (InitClass) context.getBean("initClass");
}
public class InitClass{
#Autowired
public B b;
#Autowired
public C c;
}
with this you will get B and C without using xml.
2- http://static.springsource.org/spring/docs/3.0.0.M3/reference/html/ch04s04.html Bean scopes are detailed mentioned here. If you want always a new object you should use prototype but creating a new one will be done in different classes. In the same class you should add a new reference.
like
public class InitClass{
#Autowired
public A a1;
#Autowired
public A a2;
}

Categories