Developing a Java API and including it in a Spring App - java

We have a large Spring based App that includes different modules but also custom APIs. While there are modules that need a Spring context since they just wrap parts of the domain model we think that some of our APIs do not.
For example we wrote a wrapper around Jackson / Jersey to provide and consume REST services. There is a central interface to access this API. The implementation however needs another class and that another and so on. So a simple initialization would be
A a = new A(new B(new C(), new D(new E())))
Which we currently are saved from using #Inject. The context for this API scans the package and then gets imported into the target app.
<import resource="classpath:api-context.xml" />
We don't feel that comfortable with this and want to kick the spring context out of the REST wrapper, meaning we want the API not to require one, but are not sure how to do it. It should mean either of the following two:
constructor arguments
In the target context this will require the creation of several beans each initialized with its dependencies
<bean id="a" class="...A">
<constructor-arg>
<ref = b " />
</constructor-arg>
</bean>
<bean id="b" class="...B">
<constructor-arg>
<ref = c " />
</constructor-arg>
</bean>
<!-- And so on -->
Getters and Setters
Or, assuming that A is a specific implementation of the AInterface and AInterface is the central access we could just say, A uses a certain implementation of BInterface by default and so on and actually set them internally with new:
public class A implements AInterface {
private BInterface b = new B();
public getB() {return b;}
public setB(B b) {this.b = b) }
}
// and so on
Then in my target context I can initialize the central access with one line if I want to use the default configuration
<bean id="a" class="...A" />
or use properties to set its B. Then however if I want to change something farther down the line I'd have to initialize all beans and set the properties.
Also it does not seem clean to me if I use new for a service outside my tests.
So we're wondering how do other API developers make their interfaces and beans accessible without relying on a context import (which btw also clutters up the target context with many potentially unneeded beans, like for example if an API provides several services and I only want to use one)?
edit
Not sure if any of this is better:
public class A implements AInterface {
private BInterface b
public A() {
b = new B();
}
public getB() {return b;}
public setB(B b) {this.b = b) }
}
or
public class A implements AInterface {
private BInterface b
public A(B b) {
this.b = b;
}
}
The latter feels the best from test point of view but it brings us back to the chain I described above where I'll have to initialize all depending beans in my context before I can initialize A. That feels like too much configuration overhead.
One could argue that that's quite normal that all dependencies need to be initialized before using a class and that we should refactor our code. Then however we'll end up with a lot of utility / helper classes which are also not the best design as they are hard to replace or test.

Basically, if your API does not need the Spring context, there is really no reason for putting it there.
Please note that the second method you suggested:
public class A implements AInterface {
private BInterface b = new B();
public getB() {return b;}
public setB(B b) {this.b = b) }
}
Its a bit problematic becasue you initialize interface inside your class, that will cause you problems with testing since you cannot mock these objects. A better solution is to initialize it in the constructor of the class using it.

Just define all your beans to load lazily by default, and then you won't instantiate services you don't use.
<beans default-lazy-init="true">
<!-- no beans will be pre-instantiated... -->
</beans>
See http://static.springsource.org/spring/docs/2.0.x/reference/beans.html#beans-factory-lazy-init for more details.

Related

How to set multiple targets to ProxyFactoryBean and invoke one of the target method based on Config?

In java I want to implement proxy class (proxy Factory Bean) which will take multiple targets(implementing same interface) and invoke one of the target method based configuration value.
Dog & Cat implementing Animal and based on some configuration value(Y or N) want to invoke one of its implementations. This can be done using strategy but my problem is that similar logic need to applied for other implementations which are implementing different interfaces.(Example below I added below Audi and Benz classes implementing Car Interface) and want to choose of the implementations based on the configuration.
public interface Animal
{
public void sound();
}
public class Dog implements Animal
{
public void sound()
{
System.out.print("bark");
}
}
public class Cat implements Animal
{
public void sound()
{
System.out.print("Meow");
}
}
2nd bean:
public interface Car
{
public void make();
}
public class Audi implements Car
{
public void make()
{
System.out.print("Audi");
}
}
public class Benz implements Car
{
public void make()
{
System.out.print("Mercedes");
}
}
example spring configuration
<bean id "animalService" class="proxyFactoryBean">
<list>
<target id"Y". "class"="com.Dog">
<target id"N". "class"="com.Cat">
<list>
</bean>
<bean id "carService" class="proxyFactoryBean">
<list>
<target id"Y". "class"="com.Audi">
<target id"N". "class"="com.Benz">
<list>
</bean>
and In controller inject same interface(Car,Animal) and call original method with out any proxy injection.
Can someone please suggest how it can be done with either SpringProxyFactoryBean or custom implementation?
Basically in the proxy class, I want to check the configuration value and depending on that I want to invoke method on that particular implementation object.
If config value is Y , from the list of targets defined, get Y bean reference in the proxy and invoke method on it.
Proxies are usually used when you want to intercept the request to a method call (preferably an interface method) before the target implementation is invoked.
Spring allows this with the help of ProxyFactoryBean. You configure it to proxy one or more interfaces (different kinds) and a target implementation and one or more interceptors. When you ask for an implementation of any of these interfaces, configured interceptors get a chance to sniff but eventually the invoked method on target class is called.
Not too sure what your eventual goal is but all you are trying to do is to create an indirection and based on some condition either invoke class A implementation or Class B implementation. ProxyFactoryBean doesn't address this directly.
One of the options is to create multiple Spring managed beans for ProxyFactoryBean, one each of each implementation and get the bean from factory by name. Their id names will obviously be different.
Second option is for you to create a third class implementing the interface, assign that class as target in the Spring configuration and based on your condition either call Class A implementation of Class B implementation. Have a look at an example code snippet.
class CarDecider implements Car{
/*
either get Audi impl from BeanFactory or ApplicationContext
if they are configured beans
or create a new instance in case you don't have access to
BeanFactory and serving through singleton instance is not a
requirement
*/
public void make(){
if(<your condition for Audi true>){
beanFactory.getBean(Audi.class).make();
// OR
new Audi().make();
}else{
beanFactory.getBean(Benz.class).make();
// OR
new Benz().make();
}
}
}
Third option will be you avoid using ProxyFactoryBean completely. Register both implementations for an interface by different names and ask for them based on condition from BeanFactory.

Using autowired beans in an object created at runtime

I have a class B which implements W interface. It has a default implementation of W's method. class C and D override default implementation for which they need a service whose bean is instantiated by spring. String a and b comes from user and hence there is no way I can create a bean of B/C/D in advance. So I have a factory which creates a new object based on user parameters (it will create B/C/D based on parameters). Is there any clean way I can use service beans(aa/bb/cc/dd etc.) from inside C and D (spring autowires during server startup, at that time parameter required for instantiating B/C/D are not available) or is there any better way to solve the problem ?
Class B implements W{
String a;
String b;
B (String a, String b);
w_method(){
}
}
Class C extends B {
#Autowired
Service aa;
#Autowired
Service bb;
#Autowired
Service cc;
#override
w_method(){
}
}
Class D extends B {
#Autowired
Service dd;
#override
w_method(){
}
}
There are three possible approaches:
The fact that constructor arguments come from user doesn't mean that these objects cannot be created by Spring.
You can declare them as Spring beans of scope prototype and do the following in your factory:
public C createC(String a, String b) {
return applicationContext.getBean("c", a, b);
}
A disadvantage of this method is that your factory depends on ApplicationContext.
You can annotate these classes with #Configurable and enable AspectJ weaving. In this case Spring will configure objects of these classes even if you create them with new. See 7.8.1 Using AspectJ to dependency inject domain objects with Spring.
You can trigger autowiring manually as
applicationContext.getAutowireCapableBeanFactory().autowireBean(...);
This approach is useful when you don't have control over creation of objects that you need to autowire (servlets, etc).
I think the simplest method would be to wire the services into the factory and call setters on the B / C / D objects before you return them, rather than attempting to use #Autowired.
Or use axtavt's constructor argument method. If you want to avoid depending on ApplicationContext, you can use Lookup Method Injection, but you'll have to patch Spring per this blog post: http://nurkiewicz.blogspot.co.uk/2010/08/creating-prototype-spring-beans-on.html

Is it possible to unproxy a Spring bean?

I have a Spring bean, let's say:
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public class AImpl implements A {
public void setSomeDependency(D dependency) {
// This setter DOES NOT BELONG to interface A
}
}
<bean id="aImpl" class="AImpl"/>
Now I want to integration test it, but first I need to mock the dependency D, because it does too much stuff. Since the AImpl implements an interface and contains a transactional annotation, the generated proxy is only compatible with the interface A, so I can do this:
#Inject #Named("aImpl")
private A a;
but cannot:
#Inject #Named("aImpl")
private AImpl a;
As a result, I can't mock my dependency.
Please note that adding void setSomeDependency(D dependency) to interface A is not an option, as it has no business meaning. Neither it is using the proxy-target-class="true", as it breaks a whole lot of other beans (this attribute affects all beans in the context).
Is there a way to unproxy the injected bean A, so I could cast it to AImpl?
Try this:
if(AopUtils.isAopProxy(a) && a instanceof Advised) {
Object target = ((Advised)a).getTargetSource().getTarget();
AImpl ai = (AImpl)target;
}
Bonus: in Scala I am using the following equivalent function for the very same purpose:
def unwrapProxy(a: AnyRef) = a match {
case advised: Advised if(AopUtils.isAopProxy(advised)) =>
advised.getTargetSource.getTarget
case notProxy => notProxy
}
With the introduction of Spring 4.2.RC1, there is now a dedicated utility class in the spring-test module that handles this case for you.
The class is called AopTestUtils and provides the methods:
getTargetObject (unwraps only the top-level proxy)
getUltimateTargetObject (unwraps multiple levels of proxies if they exist).
Check out the relevant commit as well as the respective issue.

CDI with unmanaged objects

Suppose that I have two classes, first a class without any properties, fields or annotations:
public class B {}
And a class which gets B injected, like this:
public class A {
#Inject
private B b;
public B getB() {
return b;
}
}
Now class A is pretty useless until we use it, so there are two options:
#Inject it
Construct it manually, using the trusty "new A()"
If A gets injected, CDI manages it and is kind enough to inject B which has the implicit scope of #Dependent. Cool, just what I want.
However, if I manually construct A (let's say in a factory or a builder), CDI completely ignores my object and won't inject an object of type B.
Example I'm talking about when it doesn't work, here object a will always remain null:
public class Builder {
#Inject
private A a;
public static Builder ofTypeSomething() {
// do some magic here
return new Builder();
}
private Builder() {
// and some more here
}
}
Why doesn't this work?
Class A is a valid managed bean and has a valid scope, just like class B. Even if I add #Producer to the static method, it won't change anything (which is fine, cause the idea of the static method is to call it, not to inject Builder anywhere).
Dependency injection, while useful, is not magical. The way DI works is that when you ask the container for an instance of an object the container first constructs it (via new()) and then sets the dependencies (how this happens depends on your framework).
If you construct the entity yourself then the container has no idea you've constructed the entity and can't set the dependencies of the entity.
If you want to use a factory then most frameworks have some way of configuring the entity so that the container knows to make a static factory method call and not call the constructor of the entity. However, you still have to obtain your entity from the container.
Edit: This site seems to demonstrate how to use a factory in CDI.

Spring: Injecting a private inner class as an outer class's member?

I have the following class structure
public class Outer{
private Mapper a;
....
private class MapperA implements Mapper {
}
private class MapperB implements Mapper {
}
}
In my Spring config file I would like to create a an Outer bean, and assign one of MapperA or MapperB as a property. Is this possible?
<bean id="outer" class="mypackage.Outer">
<property name="a" ?????='????' />
</bean>
Edit: Some more info, based on the feedback from answers:
I got lazy with my above example. I do have a public setter/getter for the Mapper instance variable.
The reason all of the Mapper classes are inner classes is because there could potentially be many of them, and they will only ever be used in this class. I just don't want a ton of cruft classes in my project. Maybe a factory method is a better idea.
Spring can instantiate private inner classes. The actual problem with your config is that they are also non-static, so you need a <constructor-arg .../>:
<bean id="outer" class="mypackage.Outer">
<property name = "a">
<bean class = "mypackage.Outer.MapperA">
<constructor-arg ref = "outer" />
</bean>
</property>
</bean>
Normally you'd need a setter for the Mapper within Outer, and an instance of the required Mapper. But as these are:
private
inner
classes, that becomes a bit tricky (as you've identified). If you make them public, I'm sure you could creae an instance using Outer$MapperA etc. But that seems a little nasty. So:
do they need to be inner and private ?
perhaps Outer can take a String, and determine from that whether to instantiate MapperA or MapperB. i.e. there's some factory capability here.
The simplest thing to do is to really determine if they need to be inner/private. If so, then they really shouldn't be referenced within the config, which should be talking about publicly accessible classes.
As far as I know, it's impossible until you make MapperA and MapperB usual public classes.
But if you do want to keep them as inner private classes then you can "inject" them manually.
You'll need to create method with #PostInit annotation and initialize your a field there (a = new MapperA () for example, or something more complex). With this approach you should also check that initialization callbacks are switched-on in your spring configuration.

Categories

Resources