1


I have a java interface say ITest implemented by two classes Class1 and Class2. Now I have a factory class which I use to decide which implementation to return. like

if(something)
    return new Class1()
else
   return new Class2()

Problem is that I have autowired field in Class1 which doesn't get instantiated,, but the same autowiring works in other classes which were instantiated via autowiring.
Here is code for Class1

@Componene
public Class1 implements ITest{
  @Autowired
  private SomeClass obj;
}

Not sure how to get around this problem. As autowiring for SomeClass works fine in Other classes.

Sandy
  • 2,253
  • 6
  • 24
  • 33
  • You can't autowire objects if you instantiate them yourself – DamCx Jan 24 '18 at 09:05
  • how do I get around this? My factory class needs to return instance based on certain condition. So I have to instantiate manually – Sandy Jan 24 '18 at 09:10
  • What you can do is, in your Spring config, create `@Bean` corresponding to your different `Classes`, in which you'd inject, via setter or constructor, the `SomeClass` object. That way, you don't make a new in your factory, but you autowire your `Classes` in your factory. Though, I kinda discourage that, as this isn't clean code. – DamCx Jan 24 '18 at 09:14
  • 1
    It's a crime to do `new` when using spring :). Having said that, try `Prototype` bean – pvpkiran Jan 24 '18 at 09:15
  • Possible duplicate of https://stackoverflow.com/questions/3813588/how-to-inject-dependencies-into-a-self-instantiated-object-in-spring – enpy Jan 24 '18 at 09:16

4 Answers4

1

Inject applicationContext in your factory class and use it for bean creation:

@Autowired private ApplicationContext applicationContext;
......
......
         if(something){
            return applicationContext.getBean("com.xyz.Class1");
         }
......
......

OR you can use @Configurable on top of Class1 and Class2. This needs AspectJ weaving to be enabled. Spring will then magically create beans when you use new.

gargkshitiz
  • 2,130
  • 17
  • 19
1

It strongly depends of what exactly do you need, but you can:

  1. Define the object returned by factory as prototype-scope and inject it to singleton, for more details look at: https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-factory-scopes-sing-prot-interaction

Then whole magic is done by Spring

  1. If you just want to switch between two different stateless implementations you can inject both of them to factory and return an existing bean

    @Compoment class Factory { 
    
      @Autowired 
      Class1 class1Instance;
    
      @Autowired 
      Class2 classInstance;
      ...
      if(something)
        return class1Instance;
      else
       return class2Instance;
      ...
    }
    

    }

But please make sure that both injected classes have no state.

  1. Make factory managed by Spring, both classes not-managed by Spring and inject dependencies manually:

    public Class1 implements ITest{
    
      private SomeClass obj;
    
      public Class1(SomeClass obj) {
            this.obj=obj;}
    }
    

and in factory:

  @Autowired
  private SomeClass obj;
   ...
   if(something)
     return new Class1(obj);
   else
    return new Class2(obj);

At first glance looks strange, by that way you can e.g. separate domain and application/infrastructure parts.

AdamK
  • 106
  • 5
0

You could use your Main Configuration class which is annotated with @SpringBootApplication or @Configuration.

Example:

@SpringBootApplication
public class YourApp {

   public static void main(String[] args) {
       SpringApplication.run(YourApp.class, args);
   }

   @Autowired
   private CsvBeanRepository repo;

   @Bean
   public InterfaceSome some() {
       if(something) {
           return new Some(repo);
       } else {
           return new Some2(repo);
       }
   }
}

inside a @SpringBootApplication class or a @Configuration class you can @Autowire your classes normally and use them as parameters for your factory.

kaliyuga
  • 53
  • 8
-1

I would suggest to use @value annotation for this scenario.

Example

MyClass{

Object getObjectFromFactory()
{
  if(something)
    return new Class1()
 else
    return new Class2()
}

}

then you can use it like below

@Value("#{MyClass.getObjectFromFactory}")

private Object myObject;

Amir
  • 80
  • 3