Qualifier not working in spring - java

CallingApp.java
#Service
#ComponentScan(basePackages = { "com.codegeekslab.type" })
public class CallingApp {
#Autowired
#Qualifier("BasicPhone")
private Phone phone;
public CallingApp(Phone phone) {
this.phone = phone;
}
public void makeCall(int number) {
phone.openApp(number);
}
}
Phone.java
package com.geekslab.device;
public interface Phone {
public void openApp(int number);
}
BasicPhone.java
package com.codegeekslab.type;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import com.geekslab.device.Phone;
#Component("BasicPhone")
public class BasicPhone implements Phone {
{
System.out.println("BasicPhone");
}
public void openApp(int number) {
System.out.println("calling via simcard... " + number);
}
}
SmartPhone.java
package com.codegeekslab.type;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import com.geekslab.device.Phone;
#Component("SmartPhone")
public class SmartPhone implements Phone {
{
System.out.println("SmartPhone");
}
public void openApp(int number) {
System.out.println("calling via whatsapp..." + number);
}
}
Test.java
package com.codegeekslab.test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.codegeekslab.app.CallingApp;
import com.codegeekslab.type.BasicPhone;
import com.codegeekslab.type.SmartPhone;
import com.geekslab.device.Phone;
public class Test {
public static void main(String[] args) {
//ApplicationContext context =
// new GenericXmlApplicationContext("beans.xml");
//SpringHelloWorld helloSpring = context.getBean("springHelloWorld", SpringHelloWorld.class);
//comment this for xml less spring
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.scan("com.codegeekslab.app","com.codegeekslab.type");
//context.register( BasicPhone.class,SmartPhone.class,CallingApp.class);
context.refresh();
CallingApp callingApp = context.getBean("callingApp", CallingApp.class);
callingApp.makeCall(99999);
}
}
Even though i am giving qualifier as #Qualifier("BasicPhone") in CallingApp class ,I am getting Exception as follows:
No qualifying bean of type [com.geekslab.device.Phone] is defined: expected single matching bean but found 2: BasicPhone,SmartPhone

You pass phone as a constructor argument in your CallingApp service without specifying the bean.
Try either to put a qualifier at your constructor or stick to the autowire injection which is something your already do.

i removed the CallingApp class constructor and it worked.
public CallingApp(Phone phone) {
this.phone = phone;
}
As Constructor was overriding the setter method.

You need to add no argument constructor
public CallingApp(){
//do nothing
}
public CallingApp(Phone phone) {
this.phone = phone;
}

Related

how to dynamically create multiple beans of same type then gather/autowire them

let's say that in my spring(boot) yaml config file I have a list of commands:
commands: [add,delete,copy,move]
and the corresponding class in my spring(boot) project:
public class Command {
private String name;
public Command(String name) {
this.name = name;
}
public void execute() {
System.out.println(name);
}
public String getName() {
return name;
}
}
How can I dynamically/adaptively generate the right number of command beans, then gather/autowire them in a separate class as below ?
public class Menu {
#Autowired
List<Command> commands;
public void display() {
commands.forEach(cmd -> System.out.println(cmd.getName());
}
}
Thank you very much in advance for your time and your expertise.
Regards
For dynamic bean registration, you can use ImportBeanDefinitionRegistrar.
The code will be like this:
import java.util.List;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
#Configuration
#Import(CommandsConfiguration.Registrar.class)
public class CommandsConfiguration {
static class Registrar implements ImportBeanDefinitionRegistrar {
#Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) {
final List<String> commands = // read commands from environemnt/config
for (String command : commands) {
final String beanName = command + "Command";
final BeanDefinition beanDefinition = BeanDefinitionBuilder
.genericBeanDefinition(Command.class, () -> new Command(command))
.getBeanDefinition();
registry.registerBeanDefinition(beanName, beanDefinition);
}
}
}
}

Spring Boot: Type cannot be null; nested exception is java.lang.IllegalArgumentException: Type cannot be null when running Stored Procedue

Good morning, I am new to Spring Boot, and I am performing a rest service that must invoke a procedure stored in the database, the question is that you receive the mobile and must return a code and result, as shown below:
This is my code:
Main Class
package com.app.validacion;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
Controller
package com.app.validacion.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import com.app.validacion.dao.DriverBonificadosRepository;
import com.app.validacion.entity.RespuestaVo;
#RestController
public class DriverBonificadosController {
#Autowired
private DriverBonificadosRepository dao;
#GetMapping("/service/{movil}")
public RespuestaVo ConsultarMovil(#PathVariable String movil) {
return dao.validarClienteBonifiado(movil);
}
}
Repository
package com.app.validacion.dao;
import org.springframework.data.jpa.repository.query.Procedure;
import org.springframework.data.repository.CrudRepository;
import com.app.validacion.entity.DriverBonificados;
import com.app.validacion.entity.RespuestaVo;
public interface DriverBonificadosRepository extends CrudRepository<DriverBonificados, Integer> {
#Procedure(procedureName="ValidacionClienteBonificado")
RespuestaVo validarClienteBonifiado(String pMovil);
}
My entity
import javax.persistence.NamedStoredProcedureQueries;
import javax.persistence.NamedStoredProcedureQuery;
import javax.persistence.ParameterMode;
import javax.persistence.StoredProcedureParameter;
import javax.persistence.Table;
#NamedStoredProcedureQueries({
#NamedStoredProcedureQuery(
name="SPValidationClienteBonus4G",
procedureName="ValidacionClienteBonificado",
parameters = {
#StoredProcedureParameter(mode=ParameterMode.IN, name="p_movil",type=String.class),
#StoredProcedureParameter(mode=ParameterMode.OUT, name="code",type=String.class),
#StoredProcedureParameter(mode=ParameterMode.OUT, name="result",type=String.class),
})
})
#Entity
#Table
public class DriverBonificados {
#Id
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getMovil() {
return movil;
}
public void setMovil(String movil) {
this.movil = movil;
}
public String getContador() {
return contador;
}
public void setContador(String contador) {
this.contador = contador;
}
public Date getFecha_driver() {
return fecha_driver;
}
public void setFecha_driver(Date fecha_driver) {
this.fecha_driver = fecha_driver;
}
public Date getFecha_alta() {
return fecha_alta;
}
public void setFecha_alta(Date fecha_alta) {
this.fecha_alta = fecha_alta;
}
public Date getFecha_fin() {
return fecha_fin;
}
public void setFecha_fin(Date fecha_fin) {
this.fecha_fin = fecha_fin;
}
public Date getCodigo_transaccion() {
return codigo_transaccion;
}
public void setCodigo_transaccion(Date codigo_transaccion) {
this.codigo_transaccion = codigo_transaccion;
}
private String movil;
private String contador;
private Date fecha_driver;
private Date fecha_alta;
private Date fecha_fin;
private Date codigo_transaccion;
My Class RespuestaVo
package com.app.validacion.entity;
public class RespuestaVo {
private String code;
private String result;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
}
And I get the following error (the mobile parameter must be received as a String, since in the database it is found as Varchar):
Anyone have an idea how this problem could be solved? I need to consult via Stored Procedue if or if
UPDATE
Using #Query and modifying the code as follows:
package com.app.validacion.dao;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.jpa.repository.query.Procedure;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import com.app.validacion.entity.DriverBonificados;
import com.app.validacion.entity.RespuestaVo;
public interface DriverBonificadosRepository extends CrudRepository<DriverBonificados, Integer> {
#Query(nativeQuery = true,value = "call ValidacionClienteBonificado(:movil)")
RespuestaVo validarClienteBonifiado(#Param("movil") String pMovil);
}
I get the following error:
org.springframework.core.convert.ConverterNotFoundException: No
converter found capable of converting from type
[org.springframework.data.jpa.repository.query.AbstractJpaQuery$TupleConverter$TupleBackedMap]
to type [com.app.validacion.entity.RespuestaVo] at
org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:321)
~[spring-core-5.2.1.RELEASE.jar:5.2.1.RELEASE] at
org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:194)
~[spring-core-5.2.1.RELEASE.jar:5.2.1.RELEASE] at
org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:174)
~[spring-core-5.2.1.RELEASE.jar:5.2.1.RELEASE] at
org.springframework.data.repository.query.ResultProcessor$ProjectingConverter.convert(ResultProcessor.java:297)
~[spring-data-commons-2.2.1.RELEASE.jar:2.2.1.RELEASE] at
org.springframework.data.repository.query.ResultProcessor$ChainingConverter.lambda$and$0(ResultProcessor.java:217)
~[spring-data-commons-2.2.1.RELEASE.jar:2.2.1.RELEASE] at
org.springframework.data.repository.query.ResultProcessor$ChainingConverter.convert(ResultProcessor.java:228)
~[spring-data-commons-2.2.1.RELEASE.jar:2.2.1.RELEASE] at
org.springframework.data.repository.query.ResultProcessor.processResult(ResultProcessor.java:170)
~[spring-data-commons-2.2.1.RELEASE.jar:2.2.1.RELEASE] at
org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:157)
~[spring-data-jpa-2.2.1.RELEASE.jar:2.2.1.RELEASE]
SOLVED
I managed to solve my problem, using the #Query annotation, and building an interface for the response I was going to receive, in these cases with 2 methods (according to the number of parameters that I will receive), and With this I got my answer in a Json, I leave the interface code below:
public interface RespuestaVo {
String getCode();
String getResult();
}
I recommend using #Query to run Stored Procedue with Spring Boot
Try this -
#GetMapping("/service/{movil}")
public RespuestaVo ConsultarMovil(#PathVariable("movil") String movil) {
return dao.validarClienteBonifiado(movil);
}

How could I use abstract class on spring framework?

I'm the one leaning how to write a code using Spring Boot. Then when I tried to write a code that used abstract class, I got an error as below.
Description:
Parameter 0 of constructor in com.in28minutes.spring.practice.springmasterclasspractice.devicefactory.LaptopManufacturingProcess required a bean of type 'java.lang.String' that could not be found.
Action:
Consider defining a bean of type 'java.lang.String' in your configuration.
Could you guys give me an advise how I could solve the error?
Spring Boot: v2.1.4
Java: 10.0.2
Maven: 3.6.0
SpringMasterClassPracticeDeviceFactoryApplication class
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
#SpringBootApplication
public class SpringMasterClassPracticeDeviceFactoryApplication {
private static Logger LOGGER = LoggerFactory.getLogger(SpringMasterClassPracticeDeviceFactoryApplication.class);
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication
.run(SpringMasterClassPracticeDeviceFactoryApplication.class, args);
ManufacturingImpl manufacturingImpl = applicationContext.getBean(ManufacturingImpl.class);
System.out.println(manufacturingImpl);
// manufacturingImpl.manifactureProduct("Laptop Process");
LOGGER.info("{}", manufacturingImpl);
}
}
ManufacturingImpl class
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
#Component
public class ManufacturingImpl {
#Autowired
#Qualifier("laptop")
private GeneralManufacturingProcess generalManufacturingProcess;
public void manifactureProduct(String processName) {
System.out.println(generalManufacturingProcess);
generalManufacturingProcess.launchProcess();
}
}
GeneralManufacturingProcess class
public abstract class GeneralManufacturingProcess {
private String processName;
public GeneralManufacturingProcess(String processName) {
this.processName = processName;
}
public String getProcessName() {
return processName;
}
public void launchProcess() {
if (processName != null && !processName.isEmpty()) {
assembleDevice();
testDevice();
packageDevice();
storeDevice();
} else {
System.out.println("No process name was specified");
}
}
protected abstract void assembleDevice();
protected abstract void testDevice();
protected abstract void packageDevice();
protected abstract void storeDevice();
}
LaptopManufacturingProcess class
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
#Component
#Qualifier("laptop")
public class LaptopManufacturingProcess extends GeneralManufacturingProcess {
public LaptopManufacturingProcess(String processName) {
super(processName);
}
#Override
protected void assembleDevice() {
System.out.println("Assembled laptop: " + getProcessName());
}
#Override
protected void testDevice() {
System.out.println("Tested laptop: " + getProcessName());
}
#Override
protected void packageDevice() {
System.out.println("Packaged laptop: " + getProcessName());
}
#Override
protected void storeDevice() {
System.out.println("Stored laptop: " + getProcessName());
}
}
There are Multiple ways to solve this. The problem is, that the Spring Framework is trying to create an instance of LaptopManufacturingProcess with the single constructor, which accepts a String. So the Framework is trying to autowire a Bean of type String into the constructor, which simply does not work.
Basically, what you can do is the following:
create a no-args constructor, and have it pass a hardcoded string to the parent constructor:
public LaptopManufacturingProcess() {
super("String");
}
Add an #Value-Annotation to read the String from a PropertySource:
public LaptopManufacturingProcess(#Value("${property.key.here}") String processName) {
super(processName);
}
Create a Factory Bean to create instances of GeneralManufacturingProcess on demand

java.lang.IllegalArgumentException: Not a managed type in spring boot app

I am getting following error in my code
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'locationServiceImpl': Unsatisfied
dependency expressed through method 'setLocationrepo' parameter 0;
nested exception is
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'locationRepository': Invocation of init
method failed; nested exception is java.lang.IllegalArgumentException:
Not a managed type: class com.logan.location.entities.Location
This is my repository Interface
package com.logan.location.repos;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.logan.location.entities.Location;
#Repository
public interface LocationRepository extends JpaRepository<Location, Integer> {
}
This is my Service Interface
package com.logan.location.service;
import java.util.List;
import org.springframework.stereotype.Service;
import com.logan.location.entities.Location;
#Service
public interface LocationService {
Location saveLocation(Location location);
Location updateLocation(Location location);
void deleteLocation(Location location);
Location getLocationById(int id);
List<Location> getAllLocations();
}
This is my serviceImpl
package com.logan.location.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.logan.location.entities.Location;
import com.logan.location.repos.LocationRepository;
#Service
public class LocationServiceImpl implements LocationService {
private LocationRepository locationrepo;
#Autowired
public void setLocationrepo(LocationRepository locationrepo) {
this.locationrepo = locationrepo;
}
public Location saveLocation(Location location) {
// TODO Auto-generated method stub
return locationrepo.save(location);
}
public Location updateLocation(Location location) {
// TODO Auto-generated method stub
return locationrepo.save(location);
}
public void deleteLocation(Location location) {
// TODO Auto-generated method stub
locationrepo.delete(location);
}
public Location getLocationById(int id) {
// TODO Auto-generated method stub
return locationrepo.findById(id).get();
}
public List<Location> getAllLocations() {
// TODO Auto-generated method stub
return locationrepo.findAll();
}
public LocationRepository getLocationrepo() {
return locationrepo;
}
}
And this is my entity Class
package com.logan.location.entities;
import javax.persistence.Entity;
import javax.persistence.Id;
#Entity
public class Location {
#Id
private int id;
private String code;
private String name;
private String type;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
This is the starter class
package com.logan.location;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
#EntityScan("com.logan.location.entities")
#EnableJpaRepositories(basePackages = {"com.logan.location.repos"})
#SpringBootApplication
public class LocationApplication {
public static void main(String[] args) {
SpringApplication.run(LocationApplication.class, args);
}
}
It is showing my location entity class is unmanaged ,I have tried various answers but its not working ,any help??
Remove the #Repository annotation before LocationRepository. There is no need to add it.
public interface LocationRepository extends JpaRepository<Location, Integer> {
}
Also remove #EntityScan("com.logan.location.entities") and #EnableJpaRepositories(basePackages = {"com.logan.location.repos"})
#SpringBootApplication
public class LocationApplication {
public static void main(String[] args) {
SpringApplication.run(LocationApplication.class, args);
}
}
Add location repository bean like this:
#Service
public class LocationServiceImpl implements LocationService {
private LocationRepository locationrepo;
public LocationServiceImpl(LocationRepository locationrepo){
this.locationrepo = locationrepo;
}
}
Try with this.
Please add #Configuration and #ComponentScan annotations in your LocationApplication class. And also you are missing the #Column annotaions in the entity class as well and please autowire the service properly.
#Autowired
private LocationRepository locationrepo;

Specifying which validation group to use for a bean

Specs : hibernate-validator[5.2.4.Final], spring-context[4.2.2.RELEASE]
I am trying to make the solution described here work as below. But there are no constraint violations encountered & things just pass by fine. Why?
I have two beans, one parent , other child. The child definition is as below
package code;
import javax.validation.constraints.NotNull;
import org.hibernate.validator.constraints.NotBlank;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
#Service("SampleBean")
#Validated
public class SampleBean {
#NotNull(message= "value can not be null" , groups = Group1.class)
// #NotNull(message= "value can not be null")
private Integer value;
#NotNull(message= "value1 can not be null" , groups = Group2.class)
// #NotNull(message= "value can not be null" )
private Integer value1;
public Integer getValue() {
return value;
}
public void setValue(#NotNull
Integer value) {
this.value = value;
}
public Integer getValue1() {
return value1;
}
public void setValue1(Integer value1) {
this.value1 = value1;
}
}
The Parent bean definition is as below :
package code;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
#Service("SampleBeanParent")
#Validated
public class SampleBeanParent {
public void acceptChildBean(#NotNull(message = "child cannot be null")
// #Valid
#Validated(Group1.class)
SampleBean childBean) throws NoSuchMethodException, SecurityException{
System.out.println("successfully finished");
}
}
The test class is as
package code;
import java.util.ArrayList;
import java.util.List;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Test {
public static void main(String[] args) throws NoSuchMethodException, SecurityException{
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfiguration.class);
SampleBean sampleBean = (SampleBean) context.getBean("SampleBean");
try{
SampleBeanParent parent = (SampleBeanParent) context.getBean("SampleBeanParent");
parent.acceptChildBean(sampleBean);
}
catch(ConstraintViolationException e){
System.out.println("there were validation errors");
}
}
}
By The way, i have setup appropriate spring level beans as below & it works fine without groups(i have commented the validation lines in above code without groups for the working case). So this is not the problem :)
package code;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
#Configuration
#ComponentScan(basePackageClasses = {SampleBean.class})
public class SpringConfiguration {
#Bean(name = "validator")
public LocalValidatorFactoryBean initValidatorFactory(){
return new LocalValidatorFactoryBean();
}
#Bean
public MethodValidationPostProcessor initValidationPostProcessor(){
return new MethodValidationPostProcessor();
}
}
I could do that the following way. The changed classes are as follows (I removed everything from the code that seemed to be redundant/unnecessary from the particular problem point of view)
#Service("SampleBeanParent")
#Validated(Group1.class)
public class SampleBeanParent {
public void acceptChildBean(
#Valid SampleBean childBean) throws NoSuchMethodException, SecurityException {
System.out.println("successfully finished");
}
}
#Service("SampleBean")
public class SampleBean {
#NotNull(message = "value can not be null", groups = Group1.class)
private Integer value;
public Integer getValue() {
return value;
}
public void setValue(Integer value) {
this.value = value;
}
}
Please also refer to this thread: Spring #Validated in service layer, it contains several useful points, among others quoted from one of the answers:
"The #Validated annotation is only used to specify a validation group, it doesn't itself force any validation. You need to use one of the javax.validation annotations, like #Null or #Valid." - indicating that #Validated(Group1.class) SampleBean childBean in your example does not seem to be correct
The last answer is discussing the specific case when there is another annotation on the method parameter besides #Valid like in your case there was also #NotNull(message = "child cannot be null")

Categories

Resources