I am facing an issue when I use a #Transactional annotation in a class which is extended by Service class. I know that Spring does Transaction Management only when a method is invoked by a Proxy but my problem is because of this annotation I am not able to get another Service class's property's value when accessing by object directly (property is public), but same I am able to fetch through getter method.
Controller
package com.springbootdemo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class DemoController {
#Autowired
Service1 service1;
#GetMapping("/")
public void index() {
service1.doSomething();
}
}
Service1
package com.springbootdemo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class Service1 {
#Autowired
Service2 service2;
public void doSomething(){
service2.setSname("Hello");
System.out.println("sname==> "+service2.sname);
System.out.println("getSname==>"+service2.getSname());
}
}
UtilBean
package com.springbootdemo;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
#Component
public class UtilBean {
#Transactional(propagation = Propagation.REQUIRES_NEW)
public String appendString(String s1) {
return " Hi "+ s1;
}
}
Service2
package com.springbootdemo;
import org.springframework.stereotype.Component;
#Component
public class Service2 extends UtilBean{
public String sname;
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
}
application.properties
management.endpoints.web.exposure.include=*
#management.endpoints.web.exposure.exclude=loggers
#security.user.name=admin
#security.user.password=admin
spring.datasource.url=jdbc:mysql://192.168.0.10:3306/aswaraj?zeroDateTimeBehavior=convertToNull&useSSL=false
spring.datasource.username=root
spring.datasource.password=test
spring.datasource.platform=mysql
spring.session.store-type=none
security.basic.enabled=false
Output
sname==> null
getSname==>Hello
Related
I am trying to get NoUniqueBeanDefinitionException but i am not getting it any clue why i am not getting
package com.example.demo;
public interface IDateGen {
}
package com.example.demo;
import org.springframework.stereotype.Service;
#Service
public class DateGen implements IDateGen {
}
package com.example.demo;
import org.springframework.stereotype.Service;
#Service
public class DateGen2 implements IDateGen {
}
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class DateGenUtil {
#Autowired
private IDateGen dateGen;
public IDateGen getDateGen() {
return dateGen;
}
public void setDateGen(IDateGen dateGen) {
this.dateGen = dateGen;
}
}
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
#SpringBootApplication
public class Demo3Application {
public static void main(String[] args) {
ApplicationContext appContext = SpringApplication.run(Demo3Application.class, args);
DateGenUtil util = appContext.getBean(DateGenUtil.class);
System.out.println(util.getDateGen());
}
}
When i run the main method i getting
com.example.demo.DateGen#6075b2d3
Can anyone tell why i am not getting NoUniqueBeanDefinitionException ? Thanks in advance
The dependency injection first checks for autoWiring by type and then autowire by name, wen it looks for dateGen dependency in class DateGenUtil it checks by type then it is getting two Objects, then again it tries to do autoWiringByName it gets the one object
if we rename the variable like in the below code it gives the exception, hope anyone can confirm this
#Component
public class DateGenUtil {
#Autowired
//private IDateGen dateGen;
private IDateGen date;
}
I bought this new book to try to learn Spring Boot quickly. It started out well, and I easily created a REST API. But then we added CrudRepository, and I'm seeing issues with the code as described in the book. Also, there is no code available to download because the author took it down from Oreily's git repo in order to fix some things...
The issue is that if I try to build the code as the book describes (without a default constructor) I get a Java error complaining that there is no default constructor. If I add a default constructor, it builds, but Spring uses it instead of the new constructor, that requires a parameter to be passed. So when I actually call the API, like if I call the /coffees endpoint, I get a java.lang.NullPointerException: null
So how is Spring supposed to know which constructor to use, and how could it pass in values for this parameter?
Here is the controller:
package com.bw.restdemo;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
#RestController
#RequestMapping("/coffees")
class RestAPIDemoController {
private final CoffeeRepository coffeeRepository;
public RestAPIDemoController(CoffeeRepository coffeeRepository) {
this.coffeeRepository = coffeeRepository;
this.coffeeRepository.saveAll(List.of(
new Coffee("Cafe Cereza"),
new Coffee("Freedom Fuel"),
new Coffee("Cold Brew"),
new Coffee("Sumatra")
));
}
public RestAPIDemoController() {
this.coffeeRepository = null;
};
//#RequestMapping(value = "/coffees", method = RequestMethod.GET)
#GetMapping
Iterable<Coffee> getCoffees() {
return coffeeRepository.findAll();
}
#GetMapping("/{id}")
Optional<Coffee> getCoffeeById(#PathVariable String id) {
return coffeeRepository.findById(id);
}
#PostMapping
Coffee postCoffee(#RequestBody Coffee coffee) {
return coffeeRepository.save(coffee);
}
#PutMapping("/{id}")
ResponseEntity<Coffee> putCoffee(#PathVariable String id, #RequestBody Coffee coffee) {
return (!coffeeRepository.existsById(id))
? new ResponseEntity<>(coffeeRepository.save(coffee), HttpStatus.CREATED)
: new ResponseEntity<>(coffeeRepository.save(coffee), HttpStatus.OK);
}
#DeleteMapping("/{id}")
void deleteCoffee(#PathVariable String id) {
coffeeRepository.deleteById(id);
}
}
Here is where I'm defining the interface:
package com.bw.restdemo;
import org.springframework.data.repository.CrudRepository;
interface CoffeeRepository extends CrudRepository<Coffee, String> {
}
And here's the main class -- apologies for the class stuffed at the bottom.
package com.bw.restdemo;
import java.util.UUID;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class RestDemoApplication {
public static void main(String[] args) {
SpringApplication.run(RestDemoApplication.class, args);
}
}
#Entity
class Coffee {
#Id
private String id;
private String name;
public Coffee(String id, String name) {
this.id = id;
this.name = name;
}
public void setId(String id) {
this.id = id;
}
public Coffee(String name) {
this(UUID.randomUUID().toString(), name);
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
CoffeeRepository interface is missing #Repository Annotation.
Update:
Add #Repository Annotation at CoffeeRepository
Remove the default constructor from RestAPIDemoController.
package com.bw.restdemo;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
#Repository
interface CoffeeRepository extends CrudRepository<Coffee, String> {
}
Explanation
In spring framework, #Component annotation marks a java class as a bean so the component-scanning mechanism can pick it up and pull it into the application context. As #Repository serves as a specialization of #Component , it also enable annotated classes to be discovered and registered with application context.
More at HowToDoInJava - #Repository annotation in Spring Boot
I am getting the below error while starting spring boot application.
The injection point has the following annotations:
#org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type
'java.util.concurrent.atomic.AtomicReference' in your configuration.
Below is the code .
package de.summer.sampleapplayerv1;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.transaction.annotation.EnableTransactionManagement;
#SpringBootApplication(scanBasePackages = {"de.summer.sampleapplayerv1"})
#EnableConfigurationProperties
#EnableJpaRepositories (basePackages ="de.summer.sampleapplayerv1.repository")
#EnableTransactionManagement
public class Sampleapplayerv1Application {
public static void main(String[] args) {
SpringApplication.run(Sampleapplayerv1Application.class, args);
}
}
package de.summer.sampleapplayerv1.service;
import de.summer.sampleapplayerv1.domain.QueueAndPublish;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
#Slf4j
#Service
public class QueueAndPublishServiceImpl implements QueueAndPublishService{
private final AtomicReference<List<QueueAndPublish>> currentJob;
public QueueAndPublishServiceImpl(
#Qualifier("currentJob") AtomicReference<List<QueueAndPublish>> currentJob
){
this.currentJob=currentJob;
}
#Override
public QueueAndPublish getJobStatus(UUID jobId) {
return (QueueAndPublish) currentJob.get().stream()
.filter(j -> j.getJobId()==jobId)
.collect(Collectors.toList());
}
#Override
public List<QueueAndPublish> getAllJobStatus() {
return currentJob.get();
}
#Override
public QueueAndPublish getCategoryDataProcess() {
List<QueueAndPublish> processList=new ArrayList<QueueAndPublish>();
QueueAndPublish process=QueueAndPublish.builder()
.jobId(UUID.randomUUID())
.jobName("Name for Job")
.jobStatus("Not Yet Started")
.build();
Thread t1=new Thread(process.getJobId().toString()){
#Override
public void run(){
log.info("How are you doing");
process.setJobStatus("Completed");
}
};
t1.start();
processList.add(process);
currentJob.set(processList);
return process;
}
#Override
public QueueAndPublish getCatgeoryDataProcessStatus() {
return null;
}
}
package de.summer.sampleapplayerv1.domain;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.Entity;
import javax.persistence.Id;
import java.io.Serializable;
import java.util.UUID;
#Getter
#Setter
#Builder
#Entity
public class QueueAndPublish implements Serializable {
#Id
private UUID jobId;
private String jobName;
private String jobStatus;
}
If I remove the constructor, spring boot application is starting up without any errors. If included , start up is failing with unsatisfied dependency errors.
Can someone please help on what is wrong with config?
You expect Spring to create an instance of class QueueAndPublishServiceImpl for the implementation of QueueAndPublishService. This instance needs a constructor parameter of type AtomicReference<List<QueueAndPublish>> injected.
But you obviously do not define any Spring bean (Bean, Component, Service, ...) of that type.
Edit:
public QueueAndPublishServiceImpl(
#Qualifier("currentJob") AtomicReference<List<QueueAndPublish>> currentJob
){
this.currentJob=currentJob;
}
Here you define a constructor parameter to have a AtomicReference<List<QueueAndPublish>>, and even specify it with a #Qualifier. So you need to provide a Spring bean of this class with this qualifier, otherwise Spring cannot inject it into the constructor call.
Consider defining a bean of type 'java.util.concurrent.atomic.AtomicReference' in your configuration.
Means "something like" adding this to your Sampleapplayerv1Application:
#Bean("currentJob") AtomicReference<List<QueueAndPublish>> currentJob() {
// or a list implementation of your choice.
return new AtomicReference<>(new java.util.ArrayList<>());
}
I have this request and response:
#Data
public class TestRequestDto {
#Min(7)
private String name;
}
#Data
public class TestResponseDto {
private String response;
}
And I have a controller:
package com.example.validation.demo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
#Slf4j
#RestController
public class TetController {
#PostMapping("/test")
public TestResponseDto getTestResponseDto(#Valid #RequestBody TestRequestDto request){
log.info(request.getName());
TestResponseDto response = new TestResponseDto();
response.setResponse("response");
return response;
}
}
I send a post request({"name":"test"}) with an invalid name but it works. What am I doing wrong?
Starting with Boot 2.3, we also need to explicitly add the spring-boot-starter-validation dependency
I have a parent class Car & a sub class Axio. So, i'm trying to pass an argument through super("Axio") within child constructor to constructor parameter in the parent class which then assign the value into a property defined within the parent class. When i try executing the application in spring boot it throws me an exception stating
Description:
Field car in com.test.efshop.controller.HelloController required a bean of type 'com.test.efshop.Axio' that could not be found.
Action:
Consider defining a bean of type 'com.test.efshop.Axio' in your configuration.
Can anyone please tell me how to achieve this in spring boot?. My Code is as below,
// Car class
package com.test.efshop;
public class Car {
private String carName;
public String getCarName() {
return carName;
}
public void setCarName(String carName) {
this.carName = carName;
}
public Car(String carName) {
this.carName = carName;
}
public String print() {
return "Car name is : "+carName;
}
}
//sub class of car class which is Axio
package com.test.efshop;
public class Axio extends Car{
public Axio() {
super("Axio");
}
}
//main method
package com.test.efshop;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
#SpringBootApplication
public class DemoApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
//controller class
package com.test.efshop.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import com.test.efshop.Axio;
import com.test.efshop.Engine;
#Controller
public class HelloController {
#Autowired
private Axio car;
#RequestMapping(value = "/hello")
public ModelAndView print() {
return new ModelAndView("index");
}
//This is the method which i used to return the value of Car class
#RequestMapping(value = "/hello2")
#ResponseBody
public String print2() {
return car.print();
}
}
As pvpkiran commented, you can't #Autowire a class if it's not a Spring bean.
Option a) you convert the Axio class into a service or component.
#Component
public class Axio extends Car {
public Axio() {
super("Axio");
}
}
Option b) you define a bean of type Axio.
#SpringBootApplication
public class DemoApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#Bean
public Axio myAxioBean() {
return new Axio();
}
}