How to wrap Spring beans - java

I am new to spring framework..
Here is my question: How i can wrap beans in runtime onto another class?
I have classes as follows for every data struct && java type:
#Component
public class ByteCodec extends Codec<Byte> {
public ByteCodec() {
super(Byte.class);
}
public void encode(... buffer, Byte object) {
buffer.writeByte(object);
}
public Byte decode(... buffer) {
return buffer.readByte();
}
}
and this class is a managed spring singleton.
I need to wrap that codec by next class:
class OptionalCodec<T> extends Codec<Boolean> {
public OptionalCodec(Codec<T> clazz) {
}
... some implementation of encode && decode method's ...
}
How i can do this?
Hint: i want automatic wrap in RUNTIME for every Codec instance..
And how to extend Autowired annotation, like that:
#AutowireCodec(targetClass=Integer.class, canBeNull=false)
private Codec<Integer> codec;
And how to do registry of the all runtime-created codecs with map:
Map<*MyCodecInfoClass*, Codec>
??
Thanks for any replies!

Spring allows you to inject beans by types and generic types out of the box, so for your use case I don't think it is really necessary to create a new Autowired annotation. You can simply use the existing #Autowired like this:
#Autowired
private Codec<Byte> codec;
Just keep in mind that if you define more than one bean for the same generic type and you use the code above, you'll get an error because more than one bean exist with that definition. You could get around that injecting a collection instead of a single object, for example:
#Autowired
private List<Codec<Byte>> byteCodecs;
Or if you want all codecs, regardless its generic type you can simply do something like this:
#Autowired
private List<Codec<?>> allCodecs;
Regarding your question on instance wrapping, I'm not sure if I fully understand what you're trying to achieve but you can inject a codec into another codec like I stated above, or you can take a look to Spring AOP and use it to wrap calls to your beans: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html
I'm still not sure what would be the purpose of of the OptionalCodec as it will accept booleans on the encode/decode methods. The OptionalCodec is a different class than the base Codec interface, so if you do:
#Autowired
private OptionalCodec<Byte> codec;
Will inject the optional Byte codec. If you do:
#Autowired
private Codec<Byte> codec;
Will inject the original Byte codec. But if you do:
#Autowired
private Codec<Boolean> codec;
It will match all the OptionalCodec beans (because the type signature for an OptionalCodec is Codec<Boolean>) and throw an error as it will not be able to pick a single one.
That said, if you really need to fine tune the autowiring of same type of beans I suggest you to check this relevant section of Spring documentation where annotations like #Primary and #Qualifier are explained, and let you do exactly that: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-autowired-annotation-qualifiers

Related

Spring: Mixing Autowired fields and constructor arguments in a base class

Basically, I want to make this code work:
#Component
abstract class MyBaseClass(val myArg: MyArgClass) {
#Autowired
private lateinit var myInjectedBean: MyInjectedBean
fun useBothArgAndBean()
}
class MyConcreteClass(myArg: MyArgClass) : MyBaseClass(myArg)
val myConcreteClass = MyConcreteClass(obtainMyArgClass())
myConcreteClass.useBothArgAndBean()
So I have a base class with one argument in the constructor and another argument injected from the Spring context. Currently, such a setup is not possible because Spring tries to inject also MyArgClass from context and because there's no such bean (it's constructed manually) it fails on "no matching bean".
The question is how to make this scenario work. Note that I cannot use the factory-method solution mentioned here https://stackoverflow.com/a/58790893/13015027 because I need to directly call MyBaseClass constructor from MyConcreteClass constructor. Perhaps there's a trick on how to avoid that or how to force Spring not to try to inject into the base constructor or ...?
You have a quite confusing setup there, and I am not sure that you are fully aware how injection by Spring works. You can
either create a class on your own, using its constructor, or
you can let Spring create the class and inject everything, and you don't call the constructor.
When you call the constructor, Spring will not magically inject some parts of your class, just because it has seemingly the right annotations. The variable myInjectedBean will just be null.
If you want to have the ability to create the class on your own using the constructor, you should not use field injection, because you would obviously not have any possibility to initialize the field.
Then your classes MyBaseClass and MyConcreteClass would look like this:
abstract class MyBaseClass(
val myArg: MyArgClass,
private val myInjectedBean: MyInjectedBean
) {
fun useBothArgAndBean()
}
class MyConcreteClass(myArg: MyArgClass, myInjectedBean: MyInjectedBean) : MyBaseClass(myArg, myInjectedBean)
Now, as already suggested by #Sam, you can have myInjectedBean be injected while providing myArg manually by writing another component that can completely be created by Spring, because it will only autowire myInjectedBean while myArg is provided as argument for a factory method:
#Component
class MyFactory(val myInjectedBean: MyInjectedBean) {
fun createMyConcreteClass(myArg: MyArgClass) =
MyConcreteClass(myArg, myInjectedBean)
}
Then in a class, where you have an injected myFactory: MyFactory you can just call myFactory.createMyConcreteClass(myArg) and you obtain a new MyConcreteClass that has an injected myInjectedBean.
I think you still do need some sort of factory. It would pass both the bean and the additional arguments to the MyConcreteClass constructor, and would look like this:
#Component
class MyFactory(val myInjectedBean: MyInjectedBean) {
fun getMyConcreteClass(myArg: MyArgClass) =
MyConcreteClass(myArg, myInjectedBean)
}
If using that approach, none of the other classes except MyInjectedBean would need to be registered with Spring.
In fact, it's a little surprising to me that you currently have MyBaseClass annotated with #Component. What do you expect that to do, and does it work?

How to use Java reflection to create an instance of an #Autowired class

I have a postgres database which stores (as a String) the relevant class to use dependent on the information coming in from the user.
e.g. user has input Name, the database has the value NameFinder() stored against this and the code needs to create an instance of NameFinder().
I was wondering if there was a way of using reflection to instantiate this class as an #Autowired component, and then call the relevant function.
I can't seem to find a guide that uses #Autowired classes so any help would be appreciated.
For autowiring to work you need the class which uses #Autowired to be a #Component (or a child like #Service ...). https://www.baeldung.com/spring-autowire
For Spring to know what to inject, you need to define a #Bean in your Configuration
https://www.baeldung.com/spring-bean
As for the reflective instantiation in the bean:
#Bean
public Name getName(Database db) {
String nameFqn = db.getConfigTable().getNameFQN();
return (Name) Class.forName(nameFqn).getConstructor().newInstance();
}
Note this uses a no-arg public constructor. FQN means fully-qualified name, i.e. com.some.pkg.NameFinder
assuming:
package com.some.pkg;
class NameFinder implements Name {
public NameFinder(){}
}
I feel like a Spring Bean should be configurable also directly from a FQN without using reflection but I don't know how. Try reading up on a BeanFactory or something similar. Usually reflection is to be avoided.

Spring create list of beans based on properties

In a simple Spring boot application I have my component like this:
#Data
#Component
public class GenericHandler {
private String path;
private HandlerType type;
}
And my properties might look like this:
my.handlers[0].path='/vol1/abc'
my.handlers[0].type='Single'
my.handlers[1].path='/vol1/dora'
my.handlers[1].type='MultiSequence'
I tried decorating with the GenericHandler-class with #ConfigurationProperties(prefix="my.handlers") and getting a list of all component instances in a service using
#Autowired
private List<GenericHandler> handlers;
But that created just one component, ignoring the property values at all.
How can I get one component instance per my.handlers property-entry?
You need a wrapper class
#Component
#ConfigurationProperties(prefix="my.handlers")
#Data
public class GenericHandlerWrapper {
private List<GenericHandler> handlers;
...
}
Then you can autowire the GenericHandlerWrapper
Update
As #zoolway pointed out in the comments, for the properties in the question to work as it is, #ConfigurationProperties(prefix="my.handlers") should be changed to #ConfigurationProperties(prefix="my")
That's not possible. What can be done is this:
#Data
#Component
public class GenericHandler {
private List<String> path;
private List<HandlerType> type;
}
I dealt with a similar issue in a different manner. I created a factory and an interface. The factory would hold different implementations of that interface In your case, GenericHandler would be your interface. Then you write any number of implementations of your interface and each implementation is declared as a Component. So, Spring will instantiate it as bean upon a startup (you might use #Lazy(false) to force the instantiation at startup) using some infrastructure that I wrote each bean of that interface will self-insert itself into its factory. Then at any part of your code in any bean, you can use the factory to access concrete implementation (base on your property "type" for example). The beauty is that you don't need to inject all the implementations in your bean at the time of writing but access needed implementation dynamically at run-time. I found this to be a useful pattern and created an infrastructure that does most of the work for you and published it as an Open Source library called MgntUtils. The detailed description of the idea (including reference to the library) could be found here. Also detailed explanation with examples of how to use it can be found in library Javadoc here. The library is available (with source code and Javadoc) as Maven artifacts and on the Github. Also a general article about the MgntUtils library could be found here

Guice JIT annotated binding [duplicate]

Suppose I have a class that looks like this:
public class MyClass {
#Inject
public MyClass(#Foo("whatever") Bar dependency) {
// ...
}
}
And I wanted to have some custom logic that can see we're injecting an object of type Bar with an annotation of type #Foo("whatever") and construct a corresponding Bar object...something like a Guice Provider, but that gets more context information about the injection site. Does Guice let me do something like that?
What you're describing isn't possible through normal Guice: Providers are intended to be zero-argument pure functions and there's no way to plumb the injection site information into them as you would a flexible callback function.
You can approximate what you want, though, two different ways:
If you know every single possible value of #Foo's parameter, you can make your #Foo a binding annotation and bind it by providing a Annotation-compatible equals and hashCode. This provides the most intuitive experience: You can do anything with your #Foo you can do with any other type, such as using #Foo in constructors or injecting #Foo("value") Provider<Bar> barProvider.
#Override public void configure() {
for (String value : PREDEFINED_VALUES) {
bind(Bar.class)
.annotatedWith(new FooImpl(value))
.toProvider(new BarProvider(value));
}
}
If you want #Foo to work for arbitrary parameters, you'll need to extend Guice with custom injections. This won't work for constructor injection or alongside any other #Inject annotations, but it will allow you to inspect types after Guice injection is finished to augment them as you see fit (e.g. detecting and reacting to #Foo annotations on fields).
See the example in the Guice docs for more information there.
Internally, Guice's core is effectively a Map<Key, Provider>, where a Key represents a pair of a possibly-parameterized type and an optional binding annotation. The former binding annotation trick works because Guice can map your injection request to a Provider all on its own, where the latter skips Guice's map so you can inspect/construct/inject instances all on your own.
If you're willing to skip the annotation part of your solution, you could inject a BarProvider or BarFactory that exposes a forFoo(String) method, which would give you consistent injection without knowing all your String values ahead of time. This would allow you to use assisted injection or AutoFactory to generate your factory (if you want to generate one instance per call), or let you write a straightforward factory yourself for added flexibility.
public class MyClass {
private final Bar dependency;
#Inject
public MyClass(BarProvider barProvider) {
dependency = barProvider.forFoo("whatever");
// ...
}
}

Interface to concrete class conditional instantiation in Spring

I have a Spring based Java application where a lot of classes use the following autowired interface.. they work off this interface at all places.
#Autowired
private IOperatingSystemManager m_operatingSystemManager;
Right now, there is only one implementation of the interface as follows:
#Component
public class WindowsManager implements IOperatingSystemManager
{
// Windows based shenanigans
}
And the application works as expected. Spring is happy. Everybody is happy.
Alright, not everybody...
So, I want to add another concrete implementation of IOperatingSystemManager ..
#Component
public class LinuxManager implements IOperatingSystemManager
{
// Linux based shenanigans
}
What we want is the auto wiring of IOperatingSystemManager conditionally based on a properties file setting. (say.. os=windows.. basically something that is an arbitrary string and cannot be derived from system properties etc. simply because this is a dummy example. the actual managers are not OS related.)
I don't want to change any of the classes who have autowired to the interface and are working off the interface. All I need is for Spring to look at some logic that will dictate the Autowiring of the variables and wire up the right concrete instance for:
#Autowired
IOperatingSystemManager m_operatingSystemManager
at all the gazillion places.
The documentation & web search talk about profiles, condition, bean factory, qualifiers etc.. but we don't want to use Profiles; and Qualifiers seem to be needing changes to all the interface variable annotations.
Factory methods look promising, but being new to Spring, couldn't find a crisp answer.
What is a simple and recommended way to achieve this?
Instead of scanning the WindowsManager class, create one concrete instance that implements the IOperatingSystemManager interface or another one, depending on the your logical conditions.
First, remove the #Component annotation from the WindowsManager class.
Then, create and scan this #Configuration class, which will act as a factory for your beans:
#Configuration
public class OperatingSystemManagerFactory {
#Bean
public IOperatingSystemManager getOperatingSystemManager() {
if ( /* some logic that evaluates to true if windows */ ) {
return new WindowsManager();
} else {
// Linux default option ;)
return new LinuxManager();
}
}
}
With this solution, you shouldn't need to update anyone of your classes that reference the IOperatingSystemManager interface.
I dont know which version of spring you are using but you have options for this
http://www.intertech.com/Blog/spring-4-conditional-bean-configuration/
Here, as you can see, you can create a bean based on a condition that you can decide. It actully gave your example, Windows and Linux :), so i believe thats what you are looking for.
Edit:
If you are using spring-boot, you have some other Conditional annotations
http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-developing-auto-configuration.html#boot-features-condition-annotations

Categories

Resources