Use case of BeanNameAware - java

I can't figure out any use case of BeanNameAware interface except for logging the name of bean itself.
I did my research but I could not find a single person who wrote something other than just printing the bean name after the bean has been initialized. Does it have any real use case?

BeanNameAware can be used where we have an multiple classes subclassing a abstract class and would like to know the name of those particular bean in order to use their functionality, do something if bean name follows certain pattern, manipulate them, etc. Let's take an example and understand it:
abstract class Parent implements BeanNameAware {
String beanName;
void setBeanName(String beanName) {
this.beanName = beanName;
}
abstract void doFilter();
}
#Component
class Child1 extends Parent {
#Override
void doFilter() {
// some impl
}
}
#Component
class Child2 extends Parent {
#Override
void doFilter() {
// some impl
}
}
And we have a service method that takes instance of all Parent class and invokes abstract void doFilter() method implementation:
#Service
class SomeService{
#Autowired
Parent[] childs; // injecting all Child*
void doSomethingWithChilds() {
for(Parent child: childs) {
child.doFilter(); // invoking their doFilter() impl
String currentChildName = child.beanName;
// We now know the name of current child* bean
// We can use it for manipulating the child* instance
// This is useful because each child instance will have a different bean name
if(currentChildName.equals("child2")) {
// do something special with child2
}
}
}
}

Related

Springboot: Compilation error while autowiring the parent class

All,
I am trying to autowire a parent class which has a child class with additional methods. As far as I know, Spring will inject an instance of a child class to a parent class reference. To be sure, I even added a qualifier, but I am getting a compilation error. Please advice on how to resolve this.
Here is the code
Parent class:
#Service
Class Student {
void doSomething (int i) {
}
}
Child class:
#Service
#Qualifier("childclass")
Class ScholarStudent extends Student {
void doAnotherThing (int i) {
}
}
Controller:
#RestController
Class StudentController {
#Autowired
#Qualifier("childclass")
Student student;
#GetMapping(value = "/students/{studentId}")
public restCallFromFE (#PathVariable int studentId) {
student.doAnotherThing (studentId);
}
}
I get a compilation error here stating
The method doAnotherThing() is undefined for the type Student.
(Will try to attach an image here)
I can understand this is because the method is not defined in the parent class. But how do I resolve this with autowiring?
Thanks in advance to everyone who responds.
You cannot call the method of a child class from the reference to a base class that's not declared in the base class in any way.
To fix this you'll have to make your Student an interface or an abstract class that declares all the methods the child classes will have (and maybe implements some of them itself). If you don't need all of those methods in a single Student interface, just split it into multiple interfaces and autowire those which have the methods required for the concrete usage.
Try this:
#RestController
Class StudentController {
#Autowired
#Qualifier("childclass")
Student student;
#GetMapping(value = "/students/{studentId}")
public restCallFromFE(#PathVariable int studentId) {
if (student instanceof ScholarStudent) {
var scholar = (ScholarStudent)student;
scholar.doAnotherThing(studentId);
}
}
}
Note that you may want to consider looking at polymorphic methods (eg: overriding doSomething(int i) instead of creating a separate method) if you don't want consumers to know the specialised class type.

CDI bean is not injected but can be looked up

So, I wrote an extension which registers bean I am trying to create. The bean gets scanned by CDI and I can get it using:
MyInterface myInterface = CDI.current().select(MyInterface.class).get();
And I can then access myInterface.myMethod();
However, when I try to inject my bean using:
#Inject
#MyBean
MyInterface myInterface;
it is not injected and is null.
What I want to achieve is that I specify interface, which defines some methods,then my code generates instance of this interface and returns proxy of interface type:
// defined interface
#RegisterAsMyBean
interface MyInterface {
void myMethod();
}
// usage in code:
#Inject
#MyBean
MyInterface myInterface;
I declared my bean like this:
public class MyExtension implements Extension {
public void register(#Observes #WithAnnotations(RegisterAsMyBean.class) ProcessAnnotatedType<?> aType) {
Class<?> typeDef = aType.getAnnotatedType().getJavaClass();
if(typeDef.isInterface()) {
proxyTypes.add(typeDef);
aType.veto();
}
}
}
public class BeanCreator implements Bean<Object> {
#Override
public Object create(CreationalContext<Object> creationalContext) {
// my instance building logic
}
// ... other overriden methods
}
Also in META-INF/services/javax.enterprise.inject.spi.Extension I put reference to MyExtension
The problem was in bean creation lifecycle - i was trying to create bean in processAnnotatedType cycle, while I should have done that during afterBeanDiscovery cycle.
After moving my bean creation logic to appropriate cycle the bean is created and properly injected.

Inject spring bean dynamically

In a java-spring web-app I would like to be able to dynamically inject beans.
For example I have an interface with 2 different implementations:
In my app I'm using some properties file to configure injections:
#Determines the interface type the app uses. Possible values: implA, implB
myinterface.type=implA
My injections actually loaded conditionally relaying on the properties values in the properties file. For example in this case myinterface.type=implA wherever I inject MyInterface the implementation that will be injected will be ImplA (I accomplished that by extending the Conditional annotation).
I would like that during runtime - once the properties are changed the following will happen (without server restart):
The right implementation will be injected. For example when setting myinterface.type=implB ImplB will be injected where-ever MyInterface is used
Spring Environment should be refreshed with the new values and re-injected as well to beans.
I thought of refreshing my context but that creates problems.
I thought maybe to use setters for injection and re-use those setters once properties are re-configured. Is there a working practice for such a requirement?
Any ideas?
UPDATE
As some suggested I can use a factory/registry that holds both implementations (ImplA and ImplB) and returns the right one by querying the relevant property.
If I do that I still have the second challenge - the environment. for example if my registry looks like this:
#Service
public class MyRegistry {
private String configurationValue;
private final MyInterface implA;
private final MyInterface implB;
#Inject
public MyRegistry(Environmant env, MyInterface implA, MyInterface ImplB) {
this.implA = implA;
this.implB = implB;
this.configurationValue = env.getProperty("myinterface.type");
}
public MyInterface getMyInterface() {
switch(configurationValue) {
case "implA":
return implA;
case "implB":
return implB;
}
}
}
Once property has changed I should re-inject my environment. any suggestions for that?
I know I can query that env inside the method instead of constructor but this is a performance reduction and also I would like to think of an ider for re-injecting environment (again, maybe using a setter injection?).
I would keep this task as simple as possible. Instead of conditionally load one implementation of the MyInterface interface at startup and then fire an event that triggers dynamic loading of another implementation of the same interface, I would tackle this problem in a different way, that is much simpler to implement and maintain.
First of all, I'd just load all possible implementations:
#Component
public class MyInterfaceImplementationsHolder {
#Autowired
private Map<String, MyInterface> implementations;
public MyInterface get(String impl) {
return this.implementations.get(impl);
}
}
This bean is just a holder for all implementations of the MyInterface interface. Nothing magic here, just common Spring autowiring behavior.
Now, wherever you need to inject a specific implementation of MyInterface, you could do it with the help of an interface:
public interface MyInterfaceReloader {
void changeImplementation(MyInterface impl);
}
Then, for every class that needs to be notified of a change of the implementation, just make it implement the MyInterfaceReloader interface. For instance:
#Component
public class SomeBean implements MyInterfaceReloader {
// Do not autowire
private MyInterface myInterface;
#Override
public void changeImplementation(MyInterface impl) {
this.myInterface = impl;
}
}
Finally, you need a bean that actually changes the implementation in every bean that has MyInterface as an attribute:
#Component
public class MyInterfaceImplementationUpdater {
#Autowired
private Map<String, MyInterfaceReloader> reloaders;
#Autowired
private MyInterfaceImplementationsHolder holder;
public void updateImplementations(String implBeanName) {
this.reloaders.forEach((k, v) ->
v.changeImplementation(this.holder.get(implBeanName)));
}
}
This simply autowires all beans that implement the MyInterfaceReloader interface and updates each one of them with the new implementation, which is retrieved from the holder and passed as an argument. Again, common Spring autowiring rules.
Whenever you want the implementation to be changed, you should just invoke the updateImplementations method with the name of the bean of the new implementation, which is the lower camel case simple name of the class, i.e. myImplA or myImplB for classes MyImplA and MyImplB.
You should also invoke this method at startup, so that an initial implementation is set on every bean that implements the MyInterfaceReloader interface.
I solved a similar issue by using org.apache.commons.configuration.PropertiesConfiguration and org.springframework.beans.factory.config.ServiceLocatorFactoryBean:
Let VehicleRepairService be an interface:
public interface VehicleRepairService {
void repair();
}
and CarRepairService and TruckRepairService two classes that implements it:
public class CarRepairService implements VehicleRepairService {
#Override
public void repair() {
System.out.println("repair a car");
}
}
public class TruckRepairService implements VehicleRepairService {
#Override
public void repair() {
System.out.println("repair a truck");
}
}
I create an interface for a service factory:
public interface VehicleRepairServiceFactory {
VehicleRepairService getRepairService(String serviceType);
}
Let use Config as configuration class:
#Configuration()
#ComponentScan(basePackages = "config.test")
public class Config {
#Bean
public PropertiesConfiguration configuration(){
try {
PropertiesConfiguration configuration = new PropertiesConfiguration("example.properties");
configuration
.setReloadingStrategy(new FileChangedReloadingStrategy());
return configuration;
} catch (ConfigurationException e) {
throw new IllegalStateException(e);
}
}
#Bean
public ServiceLocatorFactoryBean serviceLocatorFactoryBean() {
ServiceLocatorFactoryBean serviceLocatorFactoryBean = new ServiceLocatorFactoryBean();
serviceLocatorFactoryBean
.setServiceLocatorInterface(VehicleRepairServiceFactory.class);
return serviceLocatorFactoryBean;
}
#Bean
public CarRepairService carRepairService() {
return new CarRepairService();
}
#Bean
public TruckRepairService truckRepairService() {
return new TruckRepairService();
}
#Bean
public SomeService someService(){
return new SomeService();
}
}
By using FileChangedReloadingStrategy your configuration be reload when you change the property file.
service=truckRepairService
#service=carRepairService
Having the configuration and the factory in your service, let you can get the appropriate service from the factory using the current value of the property.
#Service
public class SomeService {
#Autowired
private VehicleRepairServiceFactory factory;
#Autowired
private PropertiesConfiguration configuration;
public void doSomething() {
String service = configuration.getString("service");
VehicleRepairService vehicleRepairService = factory.getRepairService(service);
vehicleRepairService.repair();
}
}
Hope it helps.
If I understand you correctly then the goal is not to replace injected object instances but to use different implementations during interface method call depends on some condition at run time.
If it is so then you can try to look at the Sring TargetSource mechanism in combination with ProxyFactoryBean. The point is that proxy objects will be injected to beans that uses your interface, and all the interface method calls will be sent to TargetSource target.
Let's call this "Polymorphic Proxy".
Have a look at example below:
ConditionalTargetSource.java
#Component
public class ConditionalTargetSource implements TargetSource {
#Autowired
private MyRegistry registry;
#Override
public Class<?> getTargetClass() {
return MyInterface.class;
}
#Override
public boolean isStatic() {
return false;
}
#Override
public Object getTarget() throws Exception {
return registry.getMyInterface();
}
#Override
public void releaseTarget(Object target) throws Exception {
//Do some staff here if you want to release something related to interface instances that was created with MyRegistry.
}
}
applicationContext.xml
<bean id="myInterfaceFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces" value="MyInterface"/>
<property name="targetSource" ref="conditionalTargetSource"/>
</bean>
<bean name="conditionalTargetSource" class="ConditionalTargetSource"/>
SomeService.java
#Service
public class SomeService {
#Autowired
private MyInterface myInterfaceBean;
public void foo(){
//Here we have `myInterfaceBean` proxy that will do `conditionalTargetSource.getTarget().bar()`
myInterfaceBean.bar();
}
}
Also if you want to have both MyInterface implementations to be Spring beans, and the Spring context could not contains both instances at the same time then you can try to use ServiceLocatorFactoryBean with prototype target beans scope and Conditional annotation on target implementation classes. This approach can be used instead of MyRegistry.
P.S.
Probably Application Context refresh operation also can do what you want but it can cause other problems such as performance overheads.
This may be a duplicate question or at least very similar, anyway I answered this sort of question here: Spring bean partial autowire prototype constructor
Pretty much when you want a different beans for a dependency at run-time you need to use a prototype scope. Then you can use a configuration to return different implementations of the prototype bean. You will need to handle the logic on which implementation to return yourself, (they could even be returning 2 different singleton beans it doesn't matter) But say you want new beans, and the logic for returning the implementation is in a bean called SomeBeanWithLogic.isSomeBooleanExpression(), then you can make a configuration:
#Configuration
public class SpringConfiguration
{
#Bean
#Autowired
#Scope("prototype")
public MyInterface createBean(SomeBeanWithLogic someBeanWithLogic )
{
if (someBeanWithLogic .isSomeBooleanExpression())
{
return new ImplA(); // I could be a singleton bean
}
else
{
return new ImplB(); // I could also be a singleton bean
}
}
}
There should never be a need to reload the context. If for instance, you want the implementation of a bean to change at run-time, use the above. If you really need to reload your application, because this bean was used in constructors of a singleton bean or something weird, then you need to re-think your design, and if these beans are really singleton beans. You shouldn't be reloading the context to re-create singleton beans to achieve different run-time behavior, that is not needed.
Edit The first part of this answer answered the question about dynamically injecting beans. As asked, but I think the question is more of one: 'how can I change the implementation of a singleton bean at run-time'. This could be done with a proxy design pattern.
interface MyInterface
{
public String doStuff();
}
#Component
public class Bean implements MyInterface
{
boolean todo = false; // change me as needed
// autowire implementations or create instances within this class as needed
#Qualifier("implA")
#Autowired
MyInterface implA;
#Qualifier("implB")
#Autowired
MyInterface implB;
public String doStuff()
{
if (todo)
{
return implA.doStuff();
}
else
{
return implB.doStuff();
}
}
}
You can use #Resource annotation for injection as originally answered here
e.g.
#Component("implA")
public class ImplA implements MyInterface {
...
}
#Component("implB")
public class ImplB implements MyInterface {
...
}
#Component
public class DependentClass {
#Resource(name = "\${myinterface.type}")
private MyInterface impl;
}
and then set the implementation type in properties file as -
myinterface.type=implA
Be aware that - if interesting to know about - FileChangedReloadingStrategy makes your project highly dependent on the deployment conditions: the WAR/EAR should be exploded by container and your should have direct access to the file system, conditions that are not always met in all situations and environments.
You can use Spring #Conditional on a property value. Give both Beans the same name and it should work as only one Instance will be created.
Have a look here on how to use #Conditional on Services and Components:
http://blog.codeleak.pl/2015/11/how-to-register-components-using.html
public abstract class SystemService {
}
public class FooSystemService extends FileSystemService {
}
public class GoSystemService extends FileSystemService {
}
#Configuration
public class SystemServiceConf {
#Bean
#Conditional(SystemServiceCondition.class)
public SystemService systemService(#Value("${value.key}") value) {
switch (value) {
case A:
return new FooSystemService();
case B:
return new GoSystemService();
default:
throw new RuntimeException("unknown value ");
}
}
}
public class SystemServiceCondition implements Condition {
#Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
return true;
}
}

How to specify which subclass Spring should use

In my spring-based project I have a core module ('core') with a class
#Component
public class Superclass {
// stuff
}
instances of which are injected by type throughout the code like this:
public class AService {
#Autowired
private Superclass superclass;
// service stuff
}
I also have two other modules that depend on the core module and one of which (let's call it 'module1') extends Superclass:
#component
public class Subclass extends Superclass {
// overridden stuff
}
The other module ('module2') uses Superclass as is.
Now I want that when I compile and run 'child1' an instance of Subclass is used everywhere an instance of Superclass is expected. So I write a configuration class:
#Configuration
public class Module2Configuration {
#Bean
public Superclass superclass(){
return new Subclass();
}
}
When I run this I see both Superclass and Subclass instantiated which is definitely not what I want. How do specify in 'module1' which type Spring should instantiate?
You can use #Qualifier("some name") annotation.
There is more information about that: http://blogs.sourceallies.com/2011/08/spring-injection-with-resource-and-autowired/
Spring eagerly instantiates singleton beans as stated in the documentation:
By default, ApplicationContext implementations eagerly create and configure all singleton beans as part of the initialization process.
which might explain why both #Components are created.
To specifiy which implementation is provided as a dependency you might want to check on Qualifiers that enable to choose between different implementations. In combination with lazy loading this should do the trick.
Depending on your personal taste you could also use delegation instead of inheritance using a separated interface:
public interface MyService {
public String foobar(int baz);
}
public static class CommonBehavior {
// whatever is used by Superclass and Subclass
}
#Component #Lazy
public class FormerSuperClass implements MyService {
private final CommonBehavior ...;
...
}
#Component #Lazy
public class FormerSubClass implements MyService {
private final CommonBehavior ...;
...
}
Good luck!
There are 2 methods: Use #Qualifier("SubclassName") Or Mark your subclass as #Component and declare the subclass when #Autowired
In your case:
Use #Qualifier("SubclassName")
#Component
public class Superclass {
// stuff
}
#component
public class Subclass extends Superclass {
// overridden stuff
}
public class AService {
#Autowired
#Qualifier("Subclass")
private Superclass superclass;
// service stuff
}
2.Mark your subclass as #Component and declare the subclass when #Autowired
public class Superclass {
// stuff
}
#component
public class Subclass extends Superclass {
// overridden stuff
}
public class AService {
#Autowired
private Subclass subclass;
// service stuff
}

Providing DI methods in abstract classes

In most cases I have a lot of components which are having the same classes to be injected by an OSGi Declarative Service. The services will be used to execute some logic which is the same for all derived components. Therefore to avoid duplicated code it would be the best to use abstract classes. Is there any possibility to move the DI reference methods (set/unset) to an abstract class. I'm using Bnd.
For Example:
#Component
public class B implements IA {
private ServiceC sc;
#Reference
public void setServiceC(ServiceC sc) {
this.sc = sc;
}
public void execute() {
String result = executeSomethingDependendOnServiceC();
// do something with result
}
protected String executeSomethingDependendOnServiceC() {
// execute some logic
}
}
#Component
public class D implements IA {
private ServiceC sc;
#Reference
public void setServiceC(ServiceC sc) {
this.sc = sc;
}
public void execute() {
String result = executeSomethingDependendOnServiceC();
// do something different with result
}
protected String executeSomethingDependendOnServiceC() {
// execute some logic
}
}
I want to move the setter for ServiceC and the method executeSomethingDependendOnServiceC() to an abstract class. But how does it look like in OSGi in connection with Bnd annotation. Just annotate the class with #Component is not working, because A and D will create different instances of the abstract class and the #Component is alsp creating an instance.
Maybe someone experience the same problem and give me some advices how a workaround could look like. At least a best practice solution would be fine as well :)
The DS annotations must be on the class being instantiated for the component. Annotations on super classes are not supported. There is a proposal to change the in a future spec release.
What you can do is move the method to the super class, but you will need to trivially override the method in the subclass so that you can annotate it in the subclass.

Categories