Spring Cloud AWS InstantiationException thrown when using #Autowire - spring

I like the the ability to use constructors to add dependencies. Especially autowiring those dependencies.
e.g.
public class MyClass {
private final Dependency dependency;
#Autowired
public MyClass(#Qualifier("bean-id") Dependency dependency) {
this.dependency = dependency;
}
}
What I'm finding is that the Spring Cloud AWS framework throws an "InstantiationException" if the "Dependency" class above happens to be a class which is passed to a Workflow worker and is missing a default, empty constructor.
concrete example:
public class MyClass {
private final DependencyWorkflowClientExternalFactory clientFactory;
#Autowired
public MyClass(#Qualifier("bean-id") DependencyWorkflowClientExternalFactory clientFactory) {
this.clientFactory = clientFactory;
}
}
public class WorkflowInitializer {
#Autowired
private WorkflowWorker workflowWorker; //assume wired with correct credentials
public WorkflowInitialiser() {
init();
}
public init() {
workflowWorker.addWorkflowImplementationType(MyClass.class);
}
}
the above fails with:
java.lang.InstantiationException: com.mypackage.MyClass
at java.lang.Class.newInstance(Class.java:359)
I have to do something like:
public class MyClass {
#Autowired
#Qualifier("bean-id")
private Dependency dependency;
public MyClass() {
}
}
The question is:
Is it possible in the current release of the Spring Cloud framework to use the #Autowire annotation on a constructor? Is it a requirement that the annotation is added to the instance field?
I ask (and assume "yes") because Workflow workers take a class types, rather than instantiations of objects for their implementations of workflows.
As a secondary question:
Why do ActivityWorkers take instances of an object but WorkflowWorkers take classes?

This question is actually not related to Spring Cloud AWS but AWS Flow Framework for Java.
You are using the "default" WorkflowWorker which instantiates workflow implementations as POJOs. Therefore your class MyClass is not created as a Spring bean but as a POJO.
You should use the SpringWorkflowWorker provided by the AWS Flow Framework for a better integration with Spring. For more information, have a look at the AWS Flow Framework documentation explaining the integration with Spring.

Related

What is the best way to inject a singleton service into a JAX-RS/Jersey resource?

For example, what if several resource endpoints need access to some message bus to handle requests? Surely there is some way to register a singleton service class and inject it into the resources when the service class itself is NOT a resource but used by the resources.
All of the examples I've seen with providers or custom HK2 bindings refer to resources.
The closest thing I found to what I'm looking for was with this question:
Trouble creating a simple singleton class in Jersey 2 using built-in Jersey dependency injection
What is the best JAX-RS/Jersey way of doing this?
Note that the programmatic way would be most useful, I'm not using an xml file to configure the server.
If your platform supports EJB, you could use the #Singleton EJB (javax.ejb package, not javax.inject), and inject it on your resources with the #EJB annotation. Singleton EJB have also outofthebox concurrency access control.
On plain Jersey, you can use CDI application context. Declare the service class with an #ApplicationScoped annotation and inject it on your resources with #Inject. CDI will only instantiate one bean.
If you cannot annotate the service class, you can create a method that provides your service implementation an annotate it with #Produces and #ApplicationScoped.
#Produces
#ApplicationScoped
public MyService produceService() {
// instantiate your service client
}
And then use it on your resources, with:
#Inject
private MyService
Answer credit goes to #areus the answer provided here.
However, I'm providing my own answer so that I can share the code.
The Service Bean
#Singleton
public final class MyServiceBean
{
private static final AtomicInteger INSTANCES = new AtomicInteger();
private final AtomicInteger calls = new AtomicInteger();
public MyServiceBean()
{
INSTANCES.incrementAndGet();
}
public String getMessage()
{
return String.format("MyServiceBean{INSTANCES=%d, CALLED=%d}", INSTANCES.get(), calls.incrementAndGet());
}
}
The Resource Class
#Path("/messages")
public final class MyResource
{
#Inject
private MyServiceBean bean;
#GET
#Produces(MediaType.TEXT_PLAIN)
public Response handle()
{
return Response.ok(this.bean.getMessage())
.type(MediaType.TEXT_PLAIN_TYPE)
.build();
}
}
HK2 Binder
public final class MyServiceBeanBinder extends AbstractBinder
{
#Override
protected void configure()
{
bind(MyServiceBean.class).to(MyServiceBean.class).in(Singleton.class);
}
}
Then just register the binder and the resource like so:
final ResourceConfig config = new ResourceConfig();
config.register(MyResource.class);
config.register(new MyServiceBeanBinder());
Starting the server and hitting the resource multiple times yields:
MyServiceBean{INSTANCES=1, CALLED=1}
MyServiceBean{INSTANCES=1, CALLED=2}
MyServiceBean{INSTANCES=1, CALLED=3}
MyServiceBean{INSTANCES=1, CALLED=4}
MyServiceBean{INSTANCES=1, CALLED=5}

How to write the unit test case for the Classes which are annotated with #Configuration in Spring Boot application

I have a Configuration Class, which creates the bean for RedissonClient and also Creates the CacheManager. How to create the Unit Test case for this Configuration classes.
Can we write unit test case for #Configuration Class?
If we can, How we need to develop.
I prefer to write the test case in Spock Framework, with Groovy. If not, using Junit or Mockito Framework. How to write the unit test case for the Classes which are annotated with #Configuration in Spring Boot application
#Configuration
public class CacheConfiguration {
private static final String CONFIG= "Configuration";
#Value("${redis.server.url}")
private String redisUrl;
#Value("${redis.server.password}")
private String password;
#Bean
public RedissonClient redissonClient() {
Config config = new Config();
config.useSingleServer().setAddress(redisUrl).setPassword(password);
RedissonClient client = Redisson.create(config);
return client;
}
#Bean
public CacheManager redissonCacheManager(RedissonClient redissonClient) {
Map<String, CacheConfig> config = new HashMap<String, CacheConfig>();
config.put(CONFIG, new CacheConfig(24*60*1000, 12*60*1000));
return new RedissonSpringCacheManager(redissonClient, config);
}
}
I think you should realize that classes annotated with #Configuration are not really java classes, or at least you should not treat them like this. I know it sound controversial, I'll explain...
So historically spring used XML configurations to declare beans.
In spring 2.5 I guess, they've introduced an annotation based method where you put annotations #Component/#Service on classes, put #Autowired wherever you want spring to inject dependencies, then spring starts, scans the classpath, detects the beans and starts the application context with these beans.
Then Spring 3.0 has introduced a Java Configuration way of doing spring related configurations:#Configuration / #Bean in a special class.
So you should view these configuration classes as a "substitution" to the methods I've described before
Now let me ask, do you think you should test and XML bean configuration on its own? Probably not...
Do you think you should test that class has annotation #Component on it and all the necessary dependencies are autowired (with reflection or whatever)? Probably not.
So why you want to test the Java Config classes?
Here is another argument that you might find interesting
I've said that these classes are solely for spring to resolve the beans and it internally runs them. But spring doesn't just "run" them - it creates run-time wrapper for them to overcome some technicalities. Here is an example of one such thing:
Lest assume we have three beans: A,B,C such as B and C depend on A.
class A {}
class B {
private A a;
public B(A a) {this.a = a;}
}
class C {
private A a;
public C(A a) {this.a = a;}
}
All beans are expected to be singletons so we define the configuration like this:
#Configuration
public class MyConfig {
#Bean
public A a() { return new A(); }
#Bean
public B b() { return new B(a()); }
public C c() {return new C(a()); }
}
Note that we call a() in definitions of B and C
Now, let me ask you a question: If its a "regular" java code how two different invocations of method a() (in B's and C's constructor) respectively are supposed to return the same instance of A?
So spring indeed uses a lot of sophisticated code and this is what actually runs in runtime, not your class as is, but the transformed version of it and you never know what are those transformations exactly since its and internal spring thing. But is so what is the point of testing it as it is?
I believe there are more arguments like this, but the point is clear - don't test the Configuration classes on their own.
Instead you can use an integration test that will run the spring container and load all the classes required in the configuration. However, in this case you'll probably want to mock some classes (by using #MockBean for example) so it won't be a 100% accurate test.
In terms of code coverage - IMO you should exclude these classes from coverage altogether
After some research and found that, we can run the embedded redis server and we can check whether we able to connect to redis server by spin up the application. I don't if this is correct or not. But by doing so, it really takes time to complete it, took around 20 seconds. Used following dependency to test this // https://mvnrepository.com/artifact/it.ozimov/embedded-redis
testCompile group: 'it.ozimov', name: 'embedded-redis', version: '0.7.2'
#SpringBootTest(classes = [TestApp])
class CacheConfigurationSpec extends Specification {
#Shared
RedisServer redisServer;
def setupSpec() {
redisServer = RedisServer.builder()
.port(6379)
.setting("bind 127.0.0.1")
.setting("maxmemory 128M")
.build()
redisServer.start()
}
def cleanupSpec() {
if (redisServer != null) {
redisServer.stop()
}
}
#Autowired
private RedissonClient redissonClient;
def "load all contexts"() {
}
}
#SpringBootApplication
class TestApp {
static void main(String[] args){
SpringApplication.run(TestApp.class, args)
}
}

Error on injecting service: UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl

I am trying to inject service in spring boot app. However I'm getting following error:
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=RecommendationService,parent=RecommendationResourceImpl,qualifiers={},position=-1,optional=false,self=false,unqualified=null,1163111460)
Here is the code:
package com.example.test.recommendations.resources;
#Provider
public class RecommendationResourceImpl implements RecommendationResource {
#Inject
private RecommendationService recommendationService;
#Override
public List<Recommendation> get(String currency,
String entity) {
return recommendationService.getRecommendations(currency, entity));
}
}
Service interface
package com.example.test.recommendations.resources;
// imports
public interface RecommendationService {
List<Recommendation> getRecommendations(String currency, String entity);
Recommendation get(UUID uuid);
}
Service implementation
package com.example.test.recommendations.resources;
//imports
#Component
public class RecommendationServiceImpl implements RecommendationService{
#Override
public List<Recommendation> getRecommendations(String currency, String entity) {
return Collections.emptyList();
}
#Override
public Recommendation get(UUID uuid) {
return null;
}
}
What is correct way to inject services in spring boot applications?
I am using spring boot version 1.3.8 and Jersey version 2.25.1
From your stacktrace it is evident that the server cannot find the dependency bean to be injected.So initially check that the desired bean for the class is getting created during applciation start up.Verify that the service class is in the classpath for component scan to take place, otherwise include the package for scanning.
You are using the #Inject annotation instead of the spring #Autowired annotation to inject the beans.It will work fine but the first and most important difference between #Autowired and #Inject annotation is that the #Inject annotation is only available from Spring 3.0 onwards, so if you want to use annotation-driven dependency injection in Spring 2.5 then you have to use the #Autowired annotation.
Secondly, use the annotation #Service for the service layer rather than using the #Component annotation.
Indicates that an annotated class is a "Service", originally defined
by Domain-Driven Design (Evans, 2003) as "an operation offered as an
interface that stands alone in the model, with no encapsulated state."
May also indicate that a class is a "Business Service Facade" (in the
Core J2EE patterns sense), or something similar. This annotation is a
general-purpose stereotype and individual teams may narrow their
semantics and use as appropriate.
This annotation serves as a specialization of #Component, allowing for
implementation classes to be autodetected through classpath scanning.
#Service
public class RecommendationServiceImpl implements RecommendationService{
#Override
public List<Recommendation> getRecommendations(String currency, String entity) {
return Collections.emptyList();
}
#Override
public Recommendation get(UUID uuid) {
return null;
}
}
I am not an expert on using jersey with springboot , so i do not know if any configurations are causing this issue.
Maybe this thread might be of help to you more:
Dependency injection with Jersey 2.0
You probably never registered your Service with the DI-container. You can do that in your ResourceConfig, which you probably have since you are using jersey:
public class MyApplication extends ResourceConfig {
public MyApplication() {
register(new org.glassfish.hk2.utilities.binding.AbstractBinder() {
#Override
protected void configure() {
bind(RecommendationServiceImpl.class).to(RecommendationService.class).in(Singleton.class);
}
});
packages("com.example.test.recommendations.resources");
}
}
I am using hk2 without spring, so I usually annotate my interfaces with org.jvnet.hk2.annotations.Contract and the implementations with org.jvnet.hk2.annotations.Service. (note: not the spring #Service annotation), so I recommend trying that as well.

Spring Boot configuration for non-beans [duplicate]

This question already has answers here:
Injecting beans into a class outside the Spring managed context
(8 answers)
Closed 3 years ago.
Introduction
I have some business logic properties in the application.yml file.
They are loaded into the application via a #ConfigurationProperties annotated class.
How could I use these properties in a class which is not a Spring Bean? It cannot be a singleton, because many objects of it must be created during run-time.
Example
application.yml
business.foo: 2
BusinessProperties.java
#ConfigurationProperties("business")
#Getter // lombok
#Setter // lombok
public class BusinessProperties {
private int foo;
}
TypicalBean.java
#Component
public class TypicalBean {
private final BusinessProperties properties;
#Autowired
public TypicalBean(BusinessProperties properties) {
this.properties = properties;
}
#PostConstruct
public void printFoo() {
System.out.println("Foo: " + properties.getFoo()); // "Foo: 2"
}
}
NonBean.java
public class NonBean {
public void printFoo() {
System.out.println("Foo: ???"); // How to access the property?
}
}
Is there some way to create a non-singleton class, which can have access to configuration (or even other Spring beans) but otherwise works the same as a regular java class? Meaning that I can control its creation, it is collected by the garbage collector if not used anymore, etc.
You can still define the NonBean.class as a Component with Scope.Prototype
#Component
#Scope(value = BeanDefinition.SCOPE_PROTOTYPE)
public class NonBean {
#Autowired
public TypicalBean(BusinessProperties properties) {
this.properties = properties;
}
public void printFoo() {
System.out.println("Foo: " + properties.getFoo());
}
}
The trick is how you create an instance of NonBean.class. In the code where you'll be creating an instance of NonBean.class, use Spring's ObjectFactory<T>
private final ObjectFactory<NonBean> nonBeanFactory;
...
NonBean nonBean = nonBeanFactory.getObject();
The instantiated nonBean object will have been autowired.
All spring-beans creates by SpringApplicationContext. Bean - it's simple POJO-object, but created by Spring and saved in his container. If you want to get access to bean from outside of container - see this:
Getting Spring Application Context
Spring beans are really meant to be used within the application context but you might be able to achieve what you want by autowiring the properties to a static field in a Spring bean.
#Component
public class BusinessPropertiesUtils {
public static BusinessProperties INSTANCE;
#Autowired
public setBusinessProperties(BusinessProperties properties) {
this.INSTANCE = properties;
}
}
And then:
public class NonBean {
public void printFoo() {
System.out.println("Foo: " + BusinessPropertiesUtils.INSTANCE.getFoo());
}
}
PS: this is very hacky and definitely not the "Spring way".
You can configure beans with the prototype scope, which will give you a new instance of the bean every time it's requested.
From the Spring documentation:
In contrast to the other scopes, Spring does not manage the complete lifecycle of a prototype bean. The container instantiates, configures, and otherwise assembles a prototype object and hands it to the client, with no further record of that prototype instance.
...
In some respects, the Spring container’s role in regard to a prototype-scoped bean is a replacement for the Java new operator. All lifecycle management past that point must be handled by the client.
Example of how you can convert the TypicalBean class to a prototype scoped bean:
#Component
#Scope("prototype")
public class TypicalBean {
...
}
Another alternative is to manually instantiate the bean class (or any POJO) and injecting the dependencies (configuration, spring beans, etc.) through the constructor or setter methods, if you have them available or can get them from the Spring Context.
new TypicalBean(properties);

How to Initialize Jersey Application (ResourceConfig) With Spring?

I'm using Jersey 2 and Spring, and I'm trying to initialize my Jersey application (i.e. the class derived from ResourceConfig) with parameters from the Spring context.
Background: I have a single Jersey application that I build (i.e. a single WAR) and I deploy it across a server cluster with different Spring configurations on different servers to enable or disable different parts of the server, e.g. some of the servers have /search resources turned on, etc. This was really easy in Jersey 1.0: I just put,
<context:component-scan base-package="com.mycompany.resources.search"/>
in a Spring config to have Jersey scan that particular package and enable the JAX-RS resource providers in it.
Now in Jersey 2.0 the Spring <context:component-scan ... /> doesn't work, so resources have to be programmatically registered in a startup class derived from ResourceConfig:
public class MyApplication extends ResourceConfig {
public MyApplication() {
packages("com.mycompany.resources.search");
}
}
So far so good, but I need to conditionally scan that package, and I can't figure out how to get any Spring configuration into the MyApplication class. I thought that constructor injection might work:
public class MyApplication extends ResourceConfig {
#Autowired
public MyApplication(#Qualifier("my-config") MyConfiguration myConfiguration) {
if (myConfiguration.isEnabled()) {
packages("com.mycompany.resources.search");
}
}
}
However HK2 complains that it can't find a default constructor to use... so this indicates to me that DI is in play in the construction of this class, but that the DI isn't using Spring.
Similarly, using the the Spring bean lifecycle doesn't work:
public class MyApplication extends ResourceConfig implements InitializingBean {
#Autowired
private MyConfiguration myConfiguration;
public MyApplication() {
}
#Override
public void afterPropertiesSet() throws Exception {
if (myConfiguration.isEnabled()) {
packages("com.mycompany.resources.search");
}
}
}
(The afterPropertiesSet method isn't called.)
So now I'm stuck: is there any way to configure a Jersey ResourceConfig application object using Spring?
UPDATE:
I accepted #JohnR's answer below but I'll also include my eventual solution which I think is a bit cleaner. #JohnR's answer was to have the object initialized twice: first by Spring and then by Jersey/HK2. When Spring initializes the object you cache the dependencies in a static member, and then when Jersey/HK2 initializes it later you can retrieve the dependencies.
I ended up doing this:
public class MyApplication extends ResourceConfig {
public MyApplication() {
ApplicationContext rootCtx = ContextLoader.getCurrentWebApplicationContext();
MyConfiguration myConfiguration = rootCtx.getBean(MyConfiguration.class);
if (myConfiguration.isEnabled()) {
packages("com.mycompany.resources.whatever");
}
}
}
Rather than having the object initialized twice, we let Jersey/HK2 initialize it but then we retrieve the dependencies from Spring.
Both solutions are vulnerable to timing: they both assume that Spring is initialized before Jersey/HK2.
Expanding on my previous comment:
Trying to extend ResourceConfig is dangerous if you don't know what you're doing. Jersey becomes unpredictable, and if you try to subclass it into an Abstract class, Jersey crashes.
Instead, the JAX-RS specification provides us with a very useful interface called Feature: It allows you to register any classes you want as if you were configuring your own application. Furthermore, you don't need to use the awkward AbstractBinder, you just specify what contracts you register your classes with.
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import javax.ws.rs.container.DynamicFeature;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Feature;
import javax.ws.rs.core.FeatureContext;
// Don't use #Component here, we need to inject the Spring context manually.
public class MySpringFeature implements Feature {
#Context
private ServletContext servletContext;
private ApplicationContext applicationContext;
#Autowired
private MySecurityDAO mySecurityDAO;
#Autowired
private MySpringResponseFilter myResponseFilter;
#Override
public boolean configure(FeatureContext context) {
if(this.servletContext == null) {
return false; // ERROR!
}
this.applicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
if(this.applicationContext == null) {
return false; // ERROR!
}
// This is where the magic happens!
AutowireCapableBeanFactory bf = applicationContext.getAutowireCapableBeanFactory();
bf.autowireBean(this);
// From here you can get all the beans you need
// Now we take a Spring bean instance,
// and register it with its appropriate JAX-RS contract
context.register(myResponseFilter, ContainerResponseFilter.class);
// Or, we could do this instead:
SomeSecurityFilter mySecurityFilter = new SomeSecurityFilter();
mySecurityFilter.setSecurityDAO(mySecurityDAO);
context.register(mySegurityFilter, ContainerRequestFilter.class);
// Or even this:
SomeOtherSpringBean someOtherBean = applicationContext.getBean(SomeOtherSpringBean.class);
context.register(someOtherBean, SomeOtherJerseyContract.class);
// Success!
return true;
}
}
And in your ResourceConfig:
public class MyApplication extends ResourceConfig() {
public MyApplication() {
register(MySpringFeature.class);
}
}
Ta-da!
So now I'm stuck: is there any way to configure a Jersey
ResourceConfig application object using Spring?
I don't think you can configure Jersey to obtain your ResourceConfig from Spring as a Spring managed bean. It's a bit hackish, but you could do something like this. Note that you'll end up with two instance of your ResourceConfig: one managed by Spring and another by Jersey:
public class MyApplication extends ResourceConfig {
// static, available to all instances
private static MyConfiguration myConfiguration;
public MyApplication() {
// when Spring creates the first instance of MyApplication, myConfiguration
// will be null because the setter wasn't called yet
if (myConfiguration != null)
{
// second instance created by jersey... Spring will have autowired
// the first instance, and myConfiguration is static
if (myConfiguration.isEnabled())
packages("com.mycompany.resources.search");
}
}
#Autowired
public void setMyConfiguration(MyConfiguration config)
{
// instance level setter saves to a static variable to make it available for
// future instances (i.e. the one created by jersey)
MyApplication.myConfiguration = config;
}
}
Again, this is fairly hackish. You'll want to make sure Spring is initialized before Jersey and look closely at any threading issues that could occur during initialization.

Resources