Is it necessary to use #Configuration while working with spring annotations - java

I am working with a simple spring application to check #Configuration and #Bean(java based configuartion only),The program is working with both #Configuration and without it.So is it necessary to have it.
Here is my code,
Student.java
package com.cg.spring;
public class Student {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return "Student [id=" + id + ", name=" + name + "]";
}
}
Faculty.java
package com.cg.spring;
public class Faculty {
private int empId;
private String name;
public int getEmpId() {
return empId;
}
public void setEmpId(int empId) {
this.empId = empId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return "Faculty [empId=" + empId + ", name=" + name + "]";
}
}
MyConfig.java
package com.cg.spring;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class MyConfig {
#Bean
public Student stu()
{
return new Student();
}
#Bean
public Faculty fac()
{
return new Faculty();
}}
Client.java
package com.cg.spring;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Client {
public static void main(String[] args) {
ApplicationContext context=new
AnnotationConfigApplicationContext(MyConfig.class);
Student stu=(Student)context.getBean(Student.class);
Faculty fac=(Faculty)context.getBean(Faculty.class);
stu.setName("ajay");
stu.setId(101);
System.out.println(stu);
fac.setEmpId(202);
fac.setName("Kiran");
System.out.println(fac);
}}
The output is same with or without the #Configuration
Student [id=101, name=ajay]
Faculty [empId=202, name=Kiran]
Even tried with autowiring,it is also working without #Configuration
Student.java
package com.cg.spring;
import org.springframework.beans.factory.annotation.Autowired;
public class Student {
private int id;
private String name;
#Autowired
private Faculty faculty;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Faculty getFaculty() {
return faculty;
}
public void setFaculty(Faculty faculty) {
this.faculty = faculty;
}
#Override
public String toString() {
return "Student [id=" + id + ", name=" + name + "]";
}}
Client.java
package com.cg.spring;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Client {
public static void main(String[] args) {
ApplicationContext context=new
AnnotationConfigApplicationContext(MyConfig.class);
Student stu=(Student)context.getBean(Student.class);
Faculty fac=(Faculty)context.getBean(Faculty.class);
stu.setName("ajay");
stu.setId(101);
System.out.println(stu);
fac.setEmpId(202);
fac.setName("Kiran");
System.out.println(fac);
stu.setFaculty(fac);
System.out.println(stu.getFaculty());
}}

When using Java based configuration with Spring you basically have 2 options (as you already noticed). You have the option to annotate a class with #Configuration and have all the #Bean annotated methods available as beans. However you can also do this without the #Configuration annotation. The latter is called the so called lite mode.
When using #Configuration classes the beans defined in there are regular Spring beans and when calling one method from another this will always result in the same instance of a bean. Spring detects the #Configuration classes and treats them in a very special way (it will create a proxy for those classes).
When using lite-mode the #Bean methods are basically nothing more than factory methods, although they participate in (part of) the lifecycle of Spring Beans. When calling them each call will get you a new bean. Which means that, inter bean dependencies, will get you new instances each time the method gets called.

Also I realised that if #Configuration is used defining dependencies as private is not permitted.
#Configuration
public class ProgrammingConfig {
// define bean for the fortune service
#Bean
private FortuneService javaFortuneService() {
return new JavaFortuneService();
};
// define bean for java coach and inject its dependencies
#Bean
public Coach javaCoach() {
return new JavaCoach(javaFortuneService());
}
}
will yield
WARNING: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: #Bean method 'javaFortuneService' must not be private or final; change the method's modifiers to continue
Exception in thread "main" org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: #Bean method 'javaFortuneService' must not be private or final; change the method's modifiers to continue
whilst without the #Configuration annotation the program works even with a private dependency

#Configuration is required because it indicates that a class declares one or more #Bean methods and may be processed by the Spring container to generate bean definitions and service requests for those beans at runtime. #Configuration annotation used for many other reasons. For example, #Configuration is meta-annotated with #Component, therefore #Configuration classes are candidates for component scanning (typically using Spring XML's <context:component-scan/> element) and therefore may also take advantage of #Autowired/#Inject like any regular #Component. More details references are available to the following Link -
Annotation Type Configuration
#Bean annotation on methods that are declared in classes not annotated with #Configuration is known as “lite” mode. In the “lite” mode, #Bean methods cannot declare inter-bean dependencies. Ideally, one #Bean method should not invoke another #Bean method in ‘lite’ mode.
Spring recommends that #Bean methods declared within #Configuration classes for full configuration. This kind of full mode can prevent many bugs.

Related

ConfigurationProperties for final fields doesn't work

I need to set data from application.yml file to my config class but when I trying to do it I get an error:
TestConfig is annotated with #ConstructorBinding but it is defined as a regular bean which caused dependency injection to fail.
My application.yml file looks like the following:
test:
app:
id: app_id
My TestConfig class looks like this:
#Configuration
#ConfigurationProperties(prefix = "test.app")
#ConstructorBinding
public class TestConfig {
private final String id;
public TestConfig(String id) {
this.id = id;
}
}
I'm trying to do like this but it doesn't work for me.
Where I was wrong?
According to :
https://www.baeldung.com/configuration-properties-in-spring-boot#immutable-configurationproperties-binding
You will need to remove the #Configuration from your TestConfig.class.
Furthermore, it's important to emphasize that to use the constructor binding, we need to explicitly enable our configuration class either with #EnableConfigurationProperties or with #ConfigurationPropertiesScan.
--------- Edited -----
#ConfigurationProperties(prefix = "test.app")
#ConstructorBinding
public class TestConfig {
private final int id;
public TestConfig (int id)
this.id = id
}
public String getId() {
return id;
}
}
#SpringBootApplication
#ConfigurationPropertiesScan
public class YourApp{
public static void main(String[] args) {
SpringApplication.run(YourApp.class, args);
}
}

How can I make Autowired adnotation working?

I'm trying to learn spring using some internet courses. I have problem with #Autowired and I'm still getting Error: org.springframework.beans.factory.UnsatisfiedDependencyException
I have found many similar problems, but no one suits mine.
My Product class:
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table
public class Product {
#Id
private int id;
private String name;
#Column(name = "description")
private String desc;
private double price;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
}
Interface ProductRepository:
import HIB_UD_01.product.entities.Product;
import org.springframework.data.repository.CrudRepository;
public interface ProductRepository extends CrudRepository<Product, Integer> {
}
ProductdataApplication:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class ProductdataApplication {
public static void main(String[] args) {
SpringApplication.run(ProductdataApplication.class, args);
}
}
And my Test class:
import HIB_UD_01.product.entities.Product;
import HIB_UD_01.product.repos.ProductRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
#RunWith(SpringRunner.class)
#SpringBootTest
public class ProductdataApplicationTests {
#Autowired
ProductRepository repository;
#Test
public void contextLoads() {
}
#Test
public void testCreate() {
Product product = new Product();
product.setId(1);
product.setName("Iphone");
product.setDesc("Awesome");
product.setPrice(1000d);
repository.save(product);
}
}
And last,my properites file:
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=password
I should put data about product into db, but I get an error:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'HIB_UD_01.product.ProductdataApplicationTests': Unsatisfied dependency expressed through field 'repository'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'HIB_UD_01.product.repos.ProductRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
You probably have to enable repositories on your SpringBootApplication class (or in a separate configuration class):
https://www.concretepage.com/spring-boot/spring-boot-crudrepository-example
If that doesn't work, make sure your SpringBootApplication class is a package higher then the rest of your classes, so SpringBoot can autodetect your beans. (And you can try to annotate your repository with #Repository then, to make sure SpringBoot autodetects your repository.)
Also see:
https://dzone.com/articles/the-springbootapplication-annotation-example-in-ja
https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-structuring-your-code.html
OK, problem fixed. I added #Repository to ProductRepository. I cleared repository folder and download new fresh repositories.
Then I have error with time zone in connection to MySQL. So I edit my properities file:
spring.datasource.url=jdbc:mysql://localhost:3306/mydb?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
Thank you for your help!

Spring Boot Autowiring From Another Module

I am trying to establish connection between 3 modules in my project. When I try to reach my object with #Autowired error shows up. I'll explain my scenario a little bit.
MODULES
All of these modules have been connected inside of pom.xml. Lets talk about my problem.
C -> ROUTE.JAVA
.
.
.
#Autowired
public CommuniticationRepository;
#Autowired
public Core core;
.
.
.
B -> CORE
public class Core {
private int id;
private String name;
private Date date;
public Core(int id, String name, Date date) {
this.id = id;
this.name = name;
this.date = date;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
ERROR
Field communicationRepositoryin com.demo.xyz.A.RestControllers.Route required
a bean of type 'com.demo.xyz.A.CommunicationRepository' that could not be
found.
Action:
Consider defining a bean of type 'com.demo.xyz.A.CommunicationRepository' in
your configuration.
A - > REPOSITORY.JAVA
#Component
#Repository
public interface CommunicationRepository extends CrudRepository<Communication, Date> {
List<Communication> findByDate(Date date);
void countByDate(Date date);
}
You should remove #Component and #Repository from CommunicationRepository if it is a spring data JPA repository.
You should define configurations in modules A and B.
#Configuration
#EnableJpaRepositories(basePackages ={"com.demo.xyz.A"})
#EntityScan(basePackages = {"com.demo.xyz.A"})
#ComponentScan(basePackages = {"com.demo.xyz.A"})
public class ConfigA {
}
// If you have no spring managed beans in B this is not needed
// If Core should be a spring managed bean, add #Component on top of it
#Configuration
#ComponentScan(basePackages = {"com.demo.xyz.B"})
public class ConfigB {
}
Then, in C, where you bootstrap the application, you should import the configurations for module A and module B. At this point, any beans from A and B will be available for autowiring in C.
#Configuration
#Import(value = {ConfigA.class, ConfigB.class})
public class ConfigC {
}
Basically if you want to use #Autowired annotation on top of any attribute and use it, Obviously there should be an initialized bean in the spring context to Autowire it to your usages. So here your problem is in your spring context, there is no such bean to autowire.
So the solution is you need to have those beans inside your spring context, there are multiple ways to get this done,
The classes that you need beans auto initialized inside the spring context as #Component
Ex :
#Component
public class Car{
or you can manually have a configuration file which returns such beans
Ex :
#Bean
public Car setCarBean(){
return new Car();
}
And this bean returning should be inside a #Configuration class.
please refer
Then if you are really sure that you have done with this, then correct #ComponentScan should work
EDIT
#SpringBootApplication
#ComponentScan(basePackages = { "com.demo.xyz.A", "com.demo.xyz.B"})
public class Application {
Try to add scanBasePackages in the Application class.
The default scan is for the package in which the Application class.
#SpringBootApplication(scanBasePackages = "com.demo.xyz")
public class Application {...}

Unable to insert in table using hibernate

I'm using hibernate to create table and then i'm inserting the records in the table when application starts.
For inserting the record i'm using the last example of this page
Problem : Hibernate is able to create the tables but when i'm inserting the records at the application startup it is not getting inserted.
On the other hand if i use a REST service to do the same task it works perfectly fine.
Here is my JPA class.
package com.vizexperts.georbis.usermanagement.types;
import javax.persistence.*;
#Entity
public class TestMe {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
Long Id;
#Column
String name;
public TestMe(String name) {
this.name = name;
}
public Long getId() {
return Id;
}
public void setId(Long id) {
Id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Here is corresponding TestMeRepository class.
package com.vizexperts.georbis.usermanagement.types;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface TestMeRepository extends CrudRepository<TestMe, Long> {
TestMe findByName(String name);
}
And this is how i'm inserting the data.
package com.vizexperts.georbis.config;
import com.vizexperts.georbis.usermanagement.types.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
public class InitialDataConfig implements ApplicationListener<ContextRefreshedEvent>{
#Autowired
TestMeRepository testMeRepository;
#Override
public void onApplicationEvent(final ContextRefreshedEvent event) {
// Here newly saved object is returned as testMe
// when debugging i can see the auto generated **id** for
// testMe object.
TestMe testMe = testMeRepository.save(new TestMe("Test"));
}
}
And as i said if i use the following service it works.
#RequestMapping("/georbis/test")
public Response<Void> test(){
testMeRepository.save(new TestMe("working"));
return new Response<>(true, "working");
}
I think the reason is that you are missing #Component annotation on your InitialDataConfig class.
And that is why this class is not registered as a bean and onApplicationEvent method is never called.
Add the #Component annotation and it should work fine.
Alternately you can use CommandLineRunner, try this example.

Exception org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type is defined: expected single matching bean

I am practicing Spring 4; I have an Interface (Person) with 2 its implementer classes (Professor and Student). the configuration is Automatic with Java (AutomaticBeanConfiguration.java)
When I try to access Person object:
Person person = ctx.getBean(Person.class);
person.showAge();
it throws the following error in Runtime:
Exception in thread "main" org.springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type [spring.automaticconfiguration.ambiguityautowiring.solution.qualifier.practice2.Person] is defined:
expected single matching bean but found 2: student,professor
I know that #Primary and/or #Qualifier should resolve the issue, but since it is automatic java configuration, I couldn't find the right solution.
Does anyone has any clue?
in below, I attached full Error stack and whole source code. Thanks,
the full error is:
Mar 02, 2015 10:36:40 AM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext#115c6cb: startup date [Mon Mar 02 10:36:40 EST 2015]; root of context hierarchy
Exception in thread "main" org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [spring.automaticconfiguration.ambiguityautowiring.solution.qualifier.practice2.Person] is defined: expected single matching bean but found 2: student,professor
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:365)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:331)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:968)
at spring.automaticconfiguration.ambiguityautowiring.solution.qualifier.practice2.AppMain.main(AppMain.java:44)
Source Code:
public interface Person {
public String showName();
public Integer showAge();
}
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
#Component
#Qualifier("professor")
public class Professor implements Person {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String showName() {
return getName();
}
public Integer showAge() {
return getAge();
}
}
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
#Component
#Qualifier("student")
public class Student implements Person {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String showName() {
return getName();
}
public Integer showAge() {
return getAge();
}
}
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
#Configuration
#ComponentScan //For Automatic Bean Discovery aby Spring Framework
public class AutomaticBeanConfiguration {
}
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class AppMain {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(
AutomaticBeanConfiguration.class);
//Doesn't work
// expected single matching bean but found 2: student,professor
Person person = ctx.getBean(Person.class);
person.showAge();
}
}
References:
Spring in Action: covers Spring 4 , 4th edition
Tutorial Point Spring 3
That's the expected behavior. Spring has no way to know which specific implementation of the Person interface you want, so it throws that nice exception. Ask for the specific implementation, either:
Person person = ctx.getBean(Student.class);
or:
Person person = ctx.getBean(Professor.class);
Or you could also use getBeansOfType() method to retrieve all beans that implement the Person interface:
Map<String, Person> persons = ctx.getBeansOfType(Person.class);
The key would be the name of the bean.

Categories