I have these classes. when I debug I see that the spring creates the service object in constructor and called the constructors in both classes but when I want to use the fields, they are null. What's the problem?! (type1Processor, type2Processor and type3Processor are null)
import com.vali.ReactiveSocketServer.service.ReceivedDataService;
import org.springframework.stereotype.Component;
public abstract class Processor {
public ReceivedDataService receivedDataService;
public Processor(ReceivedDataService receivedDataService) {
this.receivedDataService = receivedDataService;
}
public abstract void readStream(String stream);
}
and this is its subclass
import com.vali.ReactiveSocketServer.model.ReceivedData;
import com.vali.ReactiveSocketServer.service.ReceivedDataService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class Type1Processor extends Processor {
#Autowired
public Type1Processor(ReceivedDataService receivedDataService) {
super(receivedDataService);
}
#Override
public void readStream(String stream) {
System.out.println("readStream "+ getClass().getSimpleName() + "-" + stream);
receivedDataService.add(new ReceivedData(stream.getBytes()));
}
}
and this is its usage:
import com.vali.ReactiveSocketServer.processor.Processor;
import com.vali.ReactiveSocketServer.processor.Type1Processor;
import com.vali.ReactiveSocketServer.processor.Type2Processor;
import com.vali.ReactiveSocketServer.processor.Type3Processor;
import com.vali.ReactiveSocketServer.receivers.AppServer;
import com.vali.ReactiveSocketServer.socket.ClientHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import java.util.HashMap;
import java.util.Map;
#SpringBootApplication
public class ReactiveSocketServerApplication {
private AppServer appServer;
#Autowired
Type1Processor type1Processor;
#Autowired
Type2Processor type2Processor;
#Autowired
Type3Processor type3Processor;
public static void main(String[] args) {
SpringApplication.run(ReactiveSocketServerApplication.class, args);
ReactiveSocketServerApplication reactiveSocketServerApplication = new ReactiveSocketServerApplication();
reactiveSocketServerApplication.Start();
}
public void Start(){
appServer = AppServer.getInstance();
Map<Integer, Processor> processorMap = new HashMap<>();
processorMap.put(7001, type1Processor);
processorMap.put(7002, type2Processor);
processorMap.put(7003, type3Processor);
appServer.initialize(processorMap);
new ClientHandler(7001, 1000);
new ClientHandler(7002, 5000);
}
}
You are instantiating ReactiveSocketServerApplication yourself.
So spring can't inject the #Autowired annotated beans, because the instance was created outside of it's life cycle.
Remove this completly:
ReactiveSocketServerApplication reactiveSocketServerApplication = new ReactiveSocketServerApplication();
reactiveSocketServerApplication.Start();
And annotate your Start() with #PostConstruct:
#PostConstruct
public void Start() { ... }
You are missing #Component in the abstract class ReceivedDataService.
This mean when you create the subclases using :
#Autowired
public Type1Processor(ReceivedDataService receivedDataService) {
super(receivedDataService);
}
Can't inject ReceivedDataService and get the default value(null)
Related
In our service, we are initializing a bean (say "A") and that internally constructing a CacheableService Object by using - new CacheableService(). And as I know spring's #Cacheable annotations won't work on class method if the class is initialized using "new" Keyword.
Then what is an alternative or a way to cache method response?
Scenario :
<bean class="com.package.src.A"/>
public class A {
Map<String, CacheableService> map;
public CacheableService2() {
map = new HashedMap();
map.put("a", new CacheableService());
}
}
import org.springframework.cache.annotation.Cacheable;
public class CacheableService {
#Cacheable(value = "entityCount", key = "#criteria.toString()")
public int someEntityCount(final String criteria) {
System.out.println("Inside function : " + criteria);
return 5;
}
}
Here is a minimum example which demonstrates caching using Spring Boot. The code for the examples below can be found here.
Go to https://start.spring.io/ and create a new Spring Boot project. Make sure to include "Spring cache abstraction" which results in this entry being added to your pom:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
Add the #EnableCaching annotation to your application:
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
#EnableCaching
#SpringBootApplication
public class CacheableApplication {
public static void main(String[] args) {
SpringApplication.run(CacheableApplication.class, args);
}
}
Your service:
package com.example;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
#Service
public class CacheableService {
#Cacheable(value = "entityCount")
public int someEntityCount(final String criteria) {
System.out.print(String.format("Inside function: %s", criteria));
return 5;
}
}
Class A:
package com.example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class A {
private CacheableService cacheableService;
public A(#Autowired CacheableService cacheableService) {
this.cacheableService = cacheableService;
}
public int getEntityCount(String criteria) {
return cacheableService.someEntityCount(criteria);
}
}
And then here is a test that demonstrates that the caching is working. As you can see in the test a.getEntityCount("foo") is being called twice, but in standard out we only see "Inside function: foo" being printed once. Therefore we have verified that the second call resulted in the cache being used to produce the result.
package com.example;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import static org.junit.jupiter.api.Assertions.assertEquals;
#SpringBootTest
class CacheableTest {
private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
#Autowired
private A a;
#BeforeEach
public void init() {
System.setOut(new PrintStream(outContent));
}
#Test
public void testCaching() {
a.getEntityCount("foo");
a.getEntityCount("foo");
assertEquals("Inside function: foo", outContent.toString());
}
}
EDIT:
If you want to move the cache outside of the Spring lifecycle and manually manage it then I would recommend using Caffeine. Here is the same example but now without any Spring involved.
Your service:
package com.example.withoutspring;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import java.util.concurrent.TimeUnit;
public class CaffeineCachingService {
private LoadingCache<String, Integer> entityCountCache = Caffeine.newBuilder()
.expireAfterAccess(5, TimeUnit.MINUTES)
.build(key -> someEntityCount(key));
public int cachedEntityCount(final String criteria) {
return entityCountCache.get(criteria);
}
private int someEntityCount(final String criteria) {
System.out.print(String.format("Inside function: %s", criteria));
return 5;
}
}
Class B:
package com.example.withoutspring;
public class B {
private CaffeineCachingService cacheableService;
public B() {
cacheableService = new CaffeineCachingService();
}
public int getEntityCount(String criteria) {
return cacheableService.cachedEntityCount(criteria);
}
}
And the same test but without Spring:
package com.example.withoutspring;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class CaffeineCacheableTest {
private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
private B b = new B();
#BeforeEach
public void init() {
System.setOut(new PrintStream(outContent));
}
#Test
public void testCaching() {
b.getEntityCount("foo");
b.getEntityCount("foo");
assertEquals("Inside function: foo", outContent.toString());
}
}
Obviously you need to tune the cache to perform how you want it so probably evicting the cached values after 5 minutes is not what you want but if you visit the Caffeine Github page you will see a lot of detailed examples how to configure the cache to meet your use-case.
Hope this helps!
I'm putting together a simple Spring Boot app, and having an issue with an #Autowired field not "showing up".
My main app class:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class SpringElasticCatalogApi {
public static void main(String[] args) {
SpringApplication.run(SpringElasticCatalogApi.class, args);
}
}
My Repository class:
import com.discover.harmony.elastic.model.Customer;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Component;
import java.util.List;
#Component
public interface CustomerRepository extends ElasticsearchRepository<Customer, String> {
public Customer findByFirstName(String firstName);
public List<Customer> findByLastName(String lastName);
}
This class ("Loaders") requires an #Autowired repository field, which is NULL:
import com.discover.harmony.elastic.model.BusinessMetadata;
import com.discover.harmony.elastic.model.Customer;
//import com.discover.harmony.elastic.repository.CustomerRepository;
import com.discover.harmony.elastic.api.CustomerRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
//#Configuration
#Component
public class Loaders {
#Autowired
private CustomerRepository repository;
#PostConstruct
#Transactional
public void loadAll(){
this.repository.deleteAll();
saveCustomers();
fetchAllCustomers();
fetchIndividualCustomers();
}
private void saveCustomers() {
this.repository.save(new Customer("Alice", "Smith"));
this.repository.save(new Customer("Bob", "Smith"));
}
private void fetchAllCustomers() {
System.out.println("Customers found with findAll():");
System.out.println("-------------------------------");
for (Customer customer : this.repository.findAll()) {
System.out.println(customer);
}
System.out.println();
}
private void fetchIndividualCustomers() {
System.out.println("Customer found with findByFirstName('Alice'):");
System.out.println("--------------------------------");
System.out.println(this.repository.findByFirstName("Alice"));
System.out.println("Customers found with findByLastName('Smith'):");
System.out.println("--------------------------------");
for (Customer customer : this.repository.findByLastName("Smith")) {
System.out.println(customer);
}
}
private List<BusinessMetadata> getData() {
List<BusinessMetadata> metadata = new ArrayList<>();
metadata.add(new BusinessMetadata((long)1,"TradeLine"));
metadata.add(new BusinessMetadata((long)2,"Credit Line"));
metadata.add(new BusinessMetadata((long)3,"Other Line"));
return metadata;
}
}
What should I change, to make the #Autowire work as expected here?
The problem is that your example is not complete on implementing the ElasticSearch. To proof this, turn your CustomerRepository into a class and remove ElasticsearchRepository<Customer, String> then everything goes fine.
What you need to do is adding a new Configuration class, with #EnableElasticsearchRepositories(basePackages = "com.discover.harmony.elastic.api.CustomerRepository") to scan the provided package for Spring Data repositories.
You can find a complete example here.
I am new to Spring AOP and annotations. I tried to write a simple program that uses Aspect. I am unable to figure out where I went wrong. Its doesn't print the what I have in my Aspect.
package com.business.main;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
#EnableAspectJAutoProxy
#Configuration
public class PrintMain {
public static void main(String[] args) {
// Do I always need to have this. Can't I just use #Autowired to get beans
ApplicationContext ctx = new AnnotationConfigApplicationContext(PrintMain.class);
CheckService ck = (CheckService)ctx.getBean("service");
ck.print();
}
#Bean(name="service")
public CheckService service(){
return new CheckService();
}
}
package com.business.main;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
#Aspect
#Component
public class SimpleAspect {
#Around("execution(* com.business.main.CheckService.*(..))")
public void applyAdvice(){
System.out.println("Aspect executed");
}
}
package com.business.main;
import org.springframework.stereotype.Component;
#Component
public class CheckService{
public void print(){
System.out.println("Executed service method");
}
}
Output: Executed service method
I expect to print what I have in my Aspect
I think your #Component isn't work!
Maybe, you need the #ComponentScan
#EnableAspectJAutoProxy
#ComponentScan
#Configuration
public class PrintMain {
public static void main(String[] args) {
// Do I always need to have this. Can't I just use #Autowired to get beans
ApplicationContext ctx = new AnnotationConfigApplicationContext(TNGPrintMain.class);
CheckService ck = (CheckService)ctx.getBean("service");
ck.print();
}
#Bean(name="service")
public CheckService service(){
return new CheckService();
}
}
AppConfig contains Java Configuration.
package com.wh;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableLoadTimeWeaving;
import org.springframework.context.annotation.EnableLoadTimeWeaving.AspectJWeaving;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.aspectj.EnableSpringConfigured;
#Configuration
#EnableSpringConfigured
#EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.ENABLED)
public class AppConfig {
#Bean
#Lazy
public EchoService echoService(){
return new EchoService();
}
#Bean
public InstrumentationLoadTimeWeaver loadTimeWeaver() throws Throwable {
InstrumentationLoadTimeWeaver loadTimeWeaver = new InstrumentationLoadTimeWeaver();
return loadTimeWeaver;
}
}
Service Class
package com.wh;
import org.springframework.stereotype.Service;
#Service
public class EchoService {
public void echo( String s ) {
System.out.println( s );
}
}
EchoDelegateService is the Non Bean class in which we have Autowired The required Bean.
We expect that the EchoService should get autowired.
Problem : EchoService not getting autowired. Gives an Null Pointer exception.
package com.wh;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
#Configurable( preConstruction = true, autowire = Autowire.BY_TYPE, dependencyCheck = false )
public class EchoDelegateService {
#Autowired
private EchoService echoService;
public void echo( String s ) {
echoService.echo( s );
}
}
Main Class where we are calling method of NonBean Class.
package com.wh;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MainApp {
public static void main(String[] args) {
ApplicationContext ctx =
new AnnotationConfigApplicationContext(AppConfig.class);
new EchoDelegateService().echo("hihi, it works...");
}
}
Your question already includes the answer: "... in a non-bean class". This simply does not work. All the autowiring, aspect resolving and whatever is to that, only works for beans. Thus, you definitely need to construct your EchoDelegateService via the spring factory:
EchoDelegateService myService = ctx.getBean(EchoDelegateService.class);
myService.echo("this should really work now");
I'm trying to put together an SDK that uses Spring internally through a context it manages of its own. I want the jar that gets built to be usable regardless of whether or not Spring is in use on the application that wants to use the SDK.
I have something that works when it is running on its own. However if I attempt to use the SDK inside another Spring context (in my case a Spring Boot based application) I get a org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type exception.
Try as I might I cannot understand how to get this working, or indeed what I am doing wrong. The classes below show what I'm doing, the org.example.testapp.MySDKTest fails with the exception while the org.example.test.MySDKTest successfully passes. Sorry there is so much code but I can't reproduce the issue with a simplified case.
SDK source
package org.example.mysdk;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.example.mysdk.MyService;
import org.example.mysdk.MyServiceConfiguration;
public final class MySDK {
private static ApplicationContext applicationContext;
public static <T extends MyService> T getService(Class<? extends MyService> clazz, MyServiceConfiguration configuration) {
T tmp = (T) getApplicationContext().getBean(clazz);
tmp.setConfiguration(configuration);
return tmp;
}
private static ApplicationContext getApplicationContext() {
if (applicationContext == null) {
applicationContext = new AnnotationConfigApplicationContext(SpringContext.class);
}
return applicationContext;
}
}
.
package org.example.mysdk;
import org.springframework.beans.factory.annotation.Autowired;
public abstract class MyService {
private MyServiceConfiguration configuration;
#Autowired
private MyAutowiredService myAutowiredService;
MyService() {
}
MyService(MyServiceConfiguration configuration) {
super();
this.configuration = configuration;
}
public MyServiceConfiguration getConfiguration() {
return configuration;
}
void setConfiguration(MyServiceConfiguration configuration) {
this.configuration = configuration;
}
String getSomething(String in) {
return "something + " + myAutowiredService.getThing(configuration.getValue()) + " and " + in;
}
}
.
package org.example.mysdk;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
#Service
#Scope("prototype")
public class MyServiceImpl1 extends MyService {
public MyServiceImpl1() {
}
public MyServiceImpl1(MyServiceConfiguration configuration) {
super(configuration);
}
public String method1() {
return this.getSomething("method1");
}
}
.
package org.example.mysdk;
public class MyServiceConfiguration {
private String value;
public void setValue(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
.
package org.example.mysdk;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
#Service
public class MyAutowiredService {
private String thing = "a value";
public String getThing(String in) {
return thing + " " + in;
}
#PostConstruct
void init() {
System.out.println("MyAutowiredService bean created");
}
}
.
package org.example.mysdk;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
#Configuration
#ComponentScan(basePackages = {
"org.example.mysdk"
})
public class SpringContext {
}
Tests
This first test fails with a org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type exception,
package org.example.testapp;
import static org.junit.Assert.*;
import org.example.mysdk.MyServiceConfiguration;
import org.example.mysdk.MyServiceImpl1;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = App.class, loader = AnnotationConfigContextLoader.class)
public class MySDKTest {
#Autowired
MyServiceImpl1 service;
#Test
public void test() {
MyServiceConfiguration conf = service.getConfiguration();
assertEquals(conf.getValue(), "this is the instance configuration");
}
}
.
package org.example.testapp;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.example.mysdk.MySDK;
import org.example.mysdk.MyServiceConfiguration;
import org.example.mysdk.MyServiceImpl1;
#Configuration
#ComponentScan(basePackages = {
"org.example.testapp"
})
public class App {
#Bean
public MyServiceImpl1 myServiceImpl1() {
MyServiceConfiguration configuration = new MyServiceConfiguration();
configuration.setValue("this is the instance configuration");
return MySDK.getService(MyServiceImpl1.class, configuration);
}
}
and this test succeeds,
package org.example.test;
import static org.junit.Assert.*;
import org.example.mysdk.MySDK;
import org.example.mysdk.MyServiceConfiguration;
import org.example.mysdk.MyServiceImpl1;
import org.junit.Test;
public class MySDKTest {
#Test
public void test() {
MyServiceConfiguration configuration = new MyServiceConfiguration();
configuration.setValue("this is the instance configuration");
MyServiceImpl1 service = MySDK.getService(MyServiceImpl1.class, configuration);
assertEquals(service.getConfiguration().getValue(), "this is the instance configuration");
}
}
If I've gone about this the completely wrong way I'm happy to hear suggestions of how this should be done differently!
You have to modify two files.
First App.java, it should scan for "org.example.mysdk" package to inject myAutowiredService in abstract class MyService, If not it has to be created in App.java. And the name of the MyServiceImpl1 bean must be different from myServiceImpl1 as it will conflict.
package org.example.testapp;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.example.mysdk.MySDK;
import org.example.mysdk.MyServiceConfiguration;
import org.example.mysdk.MyServiceImpl1;
#Configuration
#ComponentScan(basePackages = {
"org.example.testapp", "org.example.mysdk"
})
public class App {
#Bean
public MyServiceImpl1 myServiceImpl() {
MyServiceConfiguration configuration = new MyServiceConfiguration();
configuration.setValue("this is the instance configuration");
return MySDK.getService(MyServiceImpl1.class, configuration);
}
}
Then secondly in MySDKTest.java should inject myServiceImpl which was created in App.java
import static org.junit.Assert.*;
import org.example.mysdk.MyServiceConfiguration;
import org.example.mysdk.MyServiceImpl1;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = App.class, loader = AnnotationConfigContextLoader.class)
public class MySDKTest {
#Autowired
MyServiceImpl1 myServiceImpl;
#Test
public void createOxiAccountService() {
MyServiceConfiguration conf = myServiceImpl.getConfiguration();
assertEquals(conf.getValue(), "this is the instance configuration");
}
}