22

I have requirement to migrate old style spring project to Spring boot. Assume below code snippet I have to migrate to Spring boot style.

Here my ask , how to convert below abstract bean to @Bean ?

<bean id="sample" class="com.test.core.common.AbstractClass" abstract="true">
    <property name="sample1" ref="sample1" />
     <property name="sample2" ref="sample2" />
</bean>
spandey
  • 1,034
  • 1
  • 15
  • 30
  • 10
    You don't. You only declare the beans which have a concrete subclass of that abstract class. – JB Nizet Jan 25 '18 at 10:33
  • This [link](https://docs.spring.io/spring-javaconfig/docs/1.0.0.m3/reference/html/creating-bean-definitions.html) of the spring documentation could help you! It shows the old xml and the new Java way! – Diego Krupitza Feb 05 '18 at 13:09
  • Possible duplicate of [Bean definition inheritance with annotations?](https://stackoverflow.com/questions/23266175/bean-definition-inheritance-with-annotations) – Sasha Shpota Feb 11 '18 at 15:33

4 Answers4

19

Write your abstract base class in plain Java (without any Spring coupling) :

public abstract class AbstractClass{   
    private Sample1 sample1;
    private Sample2 sample2;

    public AbstractClass(Sample1 sample1, Sample1 sample2){
       this.sample1 = sample1;
       this.sample2 = sample2;
   }
   ... 
}

Note that adding a constructor with parameters (both for the abstract class and the concrete class) makes injection easier and dependencies clearer.

Then you have two ways :

1) Annotate the concrete class(es) with @Component.
Such as :

@Component
public class MyClass extends AbstractClass{   
    public MyClass (Sample1 sample1, Sample1 sample2){
        super(sample1, sample2);
    }
}

This first way has the advantage to be short : just an annotation to add.
But it makes de facto the subclass as a bean that may potentially be loaded by the Spring context.

2) Alternatively, declare the bean in a Configuration class.
Such as :

@Configuration
public class MyConfig{
  @Bean
   public MyClass myClass(Sample1 sample1, Sample1 sample2){
      return new MyClass(sample1, sample1);
   }
}

This second way is more verbose but has the advantage to not modify the subclass code and also let clients of the class to decide whether the class should be a bean.

Each approach has its advantages and its drawbacks.
So to use according to the concrete requirement.

davidxxx
  • 125,838
  • 23
  • 214
  • 215
  • You are welcome. Indeed. You can also read this question : https://stackoverflow.com/questions/42713799/use-autowired-in-abstract-base-class. It gives relevant information. – davidxxx Jan 25 '18 at 10:45
3

There is no need in converting this code. You only need to make the classes that extend com.test.core.common.AbstractClass declared as spring managed beans by either annotating them with @Component or @Service or declaring a method annotated with @Bean in your configuration class.

Generally "abstract bean" is not needed in Java Configuration, there is even no equivalent. It was needed in xml configuration for parameter inheritance which is now achievable with plain java methods. Find example from Stephane Nicoll who is Spring Core developer.

Sasha Shpota
  • 9,436
  • 14
  • 75
  • 148
1

Since Java has it's own mechanism of abstract classes and inheritance in place, you don't need to do the coupling of following code in your spring coupling.

<bean id="sample" class="com.test.core.common.AbstractClass" abstract="true">
    <property name="sample1" ref="sample1" />
     <property name="sample2" ref="sample2" />
</bean>

In XML config, you needed to do this to specify the template for inheritance of child beans. But since Springboot uses Java configuration, this part is handled directly with Java inheritance.

What it means is that you can declare this abstract class as a normal Java abstract class and treat only the child classes as beans without worrying about the abstract parent class.

tryingToLearn
  • 10,691
  • 12
  • 80
  • 114
1

When we want to instantiate an abstract class or an interface as a @Bean (with ), we can generally:

  1. Instantiate an anonymous inner class.

  2. Override all abstract methods! ;(

So for a Method injection, it would look like:

@Configuration
class FreakyConfig {
  @Bean
  @RequestScope // !! (stateful)
  public MyFooBarDelegate delegate() {
    return MyFooBarDelegate.of(...);
  }
  @Bean // singleton, stateless, abstract (no spring deps.)! ;)
  public MyFooBarAbstractSingletonBean() {
    return new MyFooBarAbstractSingletonBean() { // anonymous inner class!
      @Override
      protected MyFooBarDelegate fooBarDelegate() { // ...and override the (injected)/prescribed methods.
        return delegate();
      }
    };
  }
} // (stress) tested ;)

Another good(?) question: Where is that latest ("current") "spring-javaconfig/docs"???

see also:


xerx593
  • 12,237
  • 5
  • 33
  • 64
  • I got this subclassing the abstract class in the Config. Not sure why you removed your answer to my question, was my question wrong? https://stackoverflow.com/questions/76082820/design-classes-using-spring-boot-jpa-using-callbacks-of-generic-type – user2441441 Apr 24 '23 at 14:32