i did a singleton class named AcessoCliente
public class AcessoCliente {
private HashMap<String, Cliente> clientes;
private new HashMap<String, Date> clientesNaoEncontrados;
private static AcessoCliente instance;
static {
instance = new AcessoCliente();
}
public static AcessoCliente get() {
return instance;
}
private AcessoCliente() {
clientes = new HashMap<String, Cliente>();
clientesNaoEncontrados = new HashMap<String, Date>();
}
/*business*/
}
But i need to do a dependency injection of a class named ValidadorNivelDeAcessoBusiness on my singleton class
#Component
public class ValidadorNivelDeAcessoBusiness {
#Autowired
QuerysNiveisDeAcesso querysNiveisDeAcesso;
/*business*/
}
I'm trying do this dependency injection but isn't working, This is what I did:
public class AcessoCliente {
#Autowired
ValidadorNivelDeAcessoBusiness validadorNivelDeAcessoBusiness;
private HashMap<String, Cliente> clientes;
private new HashMap<String, Date> clientesNaoEncontrados;
private static AcessoCliente instance;
static {
ApplicationContext context = new AnnotationConfigApplicationContext(AcessoCliente.class);
instance = context.getBean(AcessoCliente.class);
}
public static AcessoCliente get() {
return instance;
}
private AcessoCliente() {
clientes = new HashMap<String, Cliente>();
clientesNaoEncontrados = new HashMap<String, Date>();
}
/*business*/
}
but the dependency injection isn't working and I get this error:
Error creating bean with name 'acessoCliente': Unsatisfied dependency expressed through field 'validadorNivelDeAcessoBusiness'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'my.project.business.interceptorBusiness.ValidadorNivelDeAcessoBusiness' available: expected at least 1 bean which qualifies as autowire candidate.
Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
Edit1. That's the QuerysNiveisDeAcesso class
#Component
public class QuerysNiveisDeAcesso extends QuerysClientes {
public QueryIntegratorBuilder queryBuscaNiveisDeAcesso(String[] condicoesQuery) throws Exception {
return super.executaQuery("BUSCA_NIVEIS_DE_ACESSO", condicoesQuery);
}
public QueryIntegratorBuilder queryBuscaNiveisDeAcesso() throws Exception {
return super.executaQuery("BUSCA_NIVEIS_DE_ACESSO");
}
public QueryIntegratorBuilder queryBuscaNiveisDeAcesso(String sqlWhere, String[] condicoesQuery) throws Exception {
return super.executaQuery("BUSCA_NIVEIS_DE_ACESSO", condicoesQuery, sqlWhere);
}
}
You are trying to mix Java Singleton and Spring singleton.
To make it compatible with plain java and spring both, you should make static factory method with your injected service in parameter and make a singleton's bean in #Configuration file.
public class AcessoCliente {
ValidadorNivelDeAcessoBusiness validadorNivelDeAcessoBusiness;
private HashMap<String, Cliente> clients;
private HashMap<String, Date> clientesNaoEncontrados;
private static AcessoCliente instance;
public static AcessoCliente getInstance(ValidadorNivelDeAcessoBusiness validadorNivelDeAcessoBusiness) {
if(instance == null) {
instance = new AcessoCliente(validadorNivelDeAcessoBusiness);
}
return instance;
}
private AcessoCliente(ValidadorNivelDeAcessoBusiness validadorNivelDeAcessoBusiness) {
clientes = new HashMap<String, Cliente>();
clientesNaoEncontrados = new HashMap<String, Date>();
this.validadorNivelDeAcessoBusiness = validadorNivelDeAcessoBusiness;
}
}
#Configuration
public class AcessoClienteConfiguration
{
#Bean
#Scope("singleton")
public AcessoCliente acessoCliente(ValidadorNivelDeAcessoBusiness validadorNivelDeAcessoBusiness)
{
return AcessoCliente.getInstance(validadorNivelDeAcessoBusiness);
}
}
I've tried to recreate the same issue you are having, it would seem that your dependencies in ValidadorNivelDeAcessoBusiness class is trying to load, however one of the fields in this class might be missing an #Component annotation, for the Spring application context to load.
#Component public class AcessoCliente {
#Autowired
ValidadorNivelDeAcessoBusiness validadorNivelDeAcessoBusiness;
}
#Component
public class ValidadorNivelDeAcessoBusiness {
#Autowired
QuerysNiveisDeAcesso querysNiveisDeAcesso;
}
public class QuerysNiveisDeAcesso {
// some code
}
Would produce the above error: 'acessoCliente': Unsatisfied dependency expressed through field 'validadorNivelDeAcessoBusiness'
Ensuring that all the fields in ValidadorNivelDeAcessoBusiness have an #Component got the spring application context to work i.e.:
#Component
public class QuerysNiveisDeAcesso {
// some code
}
You've completely misused the purpose of spring.
First off, there is no point in creating an application context inside the AcessoCliente class.
Application context is a "global" spring's registry objects that usually exists once in a whole application.
If you're using Plain Spring - you can create the application context right in the public static void main method. And then get the beans from there.
Next, when you create the application context, you should pass to it the configuration objects and not a single class. You can also work with component scanning, there are many techniques. But all-in-all it should accept the "rules" to configure - read find and load the beans.
Now lets return to the AccessCliente class. You've defined it as a singleton with static methods and private constructor, that's ok. But It doesn't work with spring - in fact if you're using spring, you can make this class a Singleton in a sense that there will be a single bean in the whole application context.
This is much more manageable and clear (+ no boilerplate code).
In fact all beans by default are singletons in spring universe.
The next thing to mentions is when you make is a singleton bean (a class whose instance is managed by spring) then the whole autowiring magic will start working automatically.
What you've done is a strange hybrid that won't work anyway (how spring can create a bean if its not instructed to do so, and even if it was, the constructor is private).
So, to recap, you need something like this:
public class Main {
public static void main(String [] args) {
ApplicationContext ctx = ...;
ctx.getBean(SomeClassThatStartsTheFlow.class).doSomething();
}
}
#Service
public class AcessoCliente {
#Autowired
ValidadorNivelDeAcessoBusiness validadorNivelDeAcessoBusiness;
private HashMap<String, Cliente> clientes;
private new HashMap<String, Date> clientesNaoEncontrados;
public AcessoCliente() {
clientes = new HashMap<String, Cliente>();
clientesNaoEncontrados = new HashMap<String, Date>();
}
/*business*/
}
Related
Could you please help me and clarify how should I deal with generics in Spring?
In the following example an Exception NoUniqueBeanDefinitionException: No qualifying bean of type 'java.lang.Object' available is thrown?
public class Launcher {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
FooService<String> fooService = context.getBean(FooService.class);
fooService.printVal();
}
}
I would like to notice that if I change generic to String type it works correctly.
#Service
public final class FooService<V> {
private final V v;
#Autowired
public FooService(V v) {
this.v = v;
}
public void printVal() {
System.out.println(v);
}
}
And simple configuration class.
#Configuration
#ComponentScan("service")
public class AppConfig {
#Bean
public String string() {
return "simple string";
}
}
Could you please advice me what is the best way to force the snippet to work properly?
Since Spring 4.0 it will automatically consider generics as a form of #Qualifier, as below:
#Autowired
private Item<String> strItem; // Injects the stringItem bean
#Autowired
private Item<Integer> intItem; // Injects the integerItem bean
So you should indicate the name ( in your case "string") in your constructor method.
Is it possible to Autowire fields in a dynamic class?
I am getting a class name from the database and I want to autowire this class
Short Answer
That's not possible. Spring needs to know what Beans there are for injecting them.
Long Answer
You could #Autowire every possible bean into a class and then cache them in a Map, where the Class represents the key, and the Object the value. See below simplified example:
public class MyClass{
private final Map<Class<?>, Object> cache = new HashMap<>();
#Autowired
public MyClass(Service1 s1, Service2 s2){
// registering the beans
cache.put(Service1.class, s1);
cache.put(Service2.class, s2);
}
public <T> T getService(String className) throws ClassNotFoundException{
// getting the bean
Class<?> clazz = Class.forName(className);
return (T) cache.get(clazz);
}
}
Not sure it's a good idea, but you can inject a class like mentionned here :
Injecting beans into a class outside the Spring managed context
You can try this:
import javax.annotation.PostConstruct;
#Component
public class ApplicationContextAccessor {
private static ApplicationContextAccessor instance;
#Autowired
private ApplicationContext applicationContext;
public static T getBean(Class clazz) {
return instance.applicationContext.getBean(clazz);
}
#PostConstruct
private void registerInstance() {
instance = this;
}
}
Read this post : https://www.helicaltech.com/uses-of-springs-applicationcontext-while-using-reflection/
I have a bean with singleton scope as below:
public class MyImpl implements MyInterface {
private HashMap<String, String> config = new HashMap<>();
private void load(String check) {
if ("abc".equalsIgnoreCase(check)) {
config.put("key", "val");
}
else {
config.put("key", "val_else");
}
}
#Override
public HashMap<String, String> getConfig(String check) {
load(check);
return config;
}
}
Then in other class, I inject MyImpl and try to use config as below:
#Service
public class Service {
#Inject
MyInterface impl;
public doJob(String check){
HashMap<String, String> config = impl.getConfig(check);
String myValue= config.get("key");
//some other code
}
}
If I have 100s of request/sec, and if value of check is abc for some request and and something else for other requests, would I still having different value in myValue? I tried to generalized the code as I can not share the exact code here. My question here is can we modify the property of singleton bean per request?
Create a ThreadLocal storage (see the example) to avoid the problem.
Alternatively you can change the bean scope to be REQUEST
I'm creating a Strategy Factory that loads through applicationContext all beans that have specific annotations. In my service, i would like to pass a string parameter to this factory and it should return me the correct implementation. But i'm faced with Cast Exception:
#Autowired
private ApplicationContext applicationContext;
private Map<String,Object> strategyCache = new HashMap<>();
#PostConstruct
public void init(){
Map<String, Object> annotatedBeanClasses = applicationContext.getBeansWithAnnotation(SimulationType.class);
for(Object bean : annotatedBeanClasses.values()){
SimulationType strategyAnnotation = AnnotationUtils.findAnnotation(bean.getClass(), SimulationType.class);
strategyCache.put(strategyAnnotation.platform(),bean.getClass());
}
}
public SimulationStrategy getSimulationStrategy(String platform){
SimulationStrategy strategy = (SimulationStrategy) strategyCache.get(platform);
return strategy;
}
Im my service i would like to call this way:
SimulationStrategy strategy = simulationFactory.getSimulationStrategy(platform);
And this is my strategy class:
#Component
#SimulationType(platform="costumer")
public class ProductSimulation extends SimulationTemplate {
Do Stuff....
}
You are putting the bean's Class in your Map, instead of the bean itself.
strategyCache.put(strategyAnnotation.platform(), bean.getClass());
should be
strategyCache.put(strategyAnnotation.platform(), bean);
I am newbie to Spring Framework.I have tried following example in spring.
#Path("/XZY")
#Service
#Transactional
public class XZY {
#Autowired
SampleDAO sampleDao;
#Autowired
TestDAO testDao;
#Autowired
XZYinterface xzyinterface;
#POST
#Produces("text/plain")
#Path("/checkservice")
public Response XZYservice(#FormParam("Code") String Code,
#FormParam("source") String source,
#FormParam("value") String value) {
//return xzyinterface.checkXYZService(Code,sourceName,source);
XZYinterface xyz = ServiceFactory.getXZY(999);
return xyz.checkXYZService(Code,sourceName,source);
}
}
The following code will use to create singleton object
public class Singleton {
private static sampleA sampleClassA=null;
private static SampleB sampleClassB=null;
public static XZYAbstract getXZY(long id){
if(id == 999){
if(sampleClass == null){
sampleClassA = new sampleA();
}
return sampleClass;
}
if(id == 9999){
sampleClassB = new sampleA();
}
return sampleClassB;
}
}
Interface
public interface XZYinterface {
Response XZYservice(String Code, String source,String value)
}
Abstract class and implements Interface
public class XZYAbstract implements XZYinterface {
public XZYAbstract(){
super();
}
#Autowired
SampleDAO sampleDao;
#Autowired
TestDAO testDao;
public Response checkXYZService(String Code,String source,String value){
String sample = sampleDao.getValue(code);
//..source code
}
}
The following class extends abstract class.
public class sampleA extends XZYAbstract {
//some methods.
}
If i run the application it throws following errors
SEVERE [com.sun.jersey.spi.container.ContainerResponse] The RuntimeException could not be mapped to a response, re-throwing to the HTTP container: java.lang.NullPointerException
at com.test.xyz.XZYAbstract.checkXYZService(XZYAbstract.java:112) [:]
at com.test.XYZ.XZYservice(XZY.java:140) [:]
If i call directly without singleton object, values are initialized properly using Auto wired (//return xzyinterface.checkXYZService(Code,sourceName,source);) and it's working fine.
Throw from singleton object, values(sampleDAo,testDao) are not initialized properly.
How to resolve this error?
The reason is quite trivial: it's because Spring is just a library, and not a change to the Java language. Spring doesn't instrument nor enhance constructors, so the only way to get initialized Spring bean is to get it from the Spring context.
If you call new Bean(), you becomes Bean instance untouched by Spring.
For the question how to use singleton bean: do nothing. Spring beans are Singletons by default. You can specify other scope via #org.springframework.beans.factory.config.Scope annotation. See for example #Scope("prototype") bean scope not creating new bean, how it works.