1

I have some Jpa repositories and several Entity class. I need to create a helper object for one of my Entity. Inside that helper I use @Autowire to access the Jpa repositories.

@Entity
class A {
    @Transient
    Helper helper;

    ...

}

class Helper {
    A a;
    @Autowired
    CRepository repo;

    public Helper(A a) {
        this.a = a;
    }
}

However, the repo is always null. I've tried using SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this) and @Configurable, but both of them failed. Can anybody provide some hint for me?

BTW, A is instantiated inside a rest controller.

Thanks!.

xing
  • 464
  • 9
  • 17
  • Does this answer your question? [spring autowiring not working from a non-spring managed class](https://stackoverflow.com/questions/18347518/spring-autowiring-not-working-from-a-non-spring-managed-class) – Jens Schauder Aug 30 '21 at 08:11

4 Answers4

8

You can use a BeanUtil class to get any bean that created in Springl

@Service
public class BeanUtil implements ApplicationContextAware {
    private static ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;
    }

    public static <T> T getBean(Class<T> beanClass) {
        return context.getBean(beanClass);
    }
}

Then you can get the bean.

MyBean obj = BeanUtil.getBean(MyBean.class);
Kevin
  • 211
  • 2
  • 6
0

Use constructor injection instead of field injection; this is a best practice all the time anyway. Then it's trivial to inject your A into the controller and pass it as a constructor argument.

chrylis -cautiouslyoptimistic-
  • 75,269
  • 21
  • 115
  • 152
0

@Configurable annotation works fine, but you need to use @EnableSpringConfigured annotation in any configuration class in order to make it work. Read my answer in other stackoverflow post: spring autowiring not working from a non-spring managed class

Entity class should not contain any helpers, even if transient. For a clean design you need to separate concerns, so the entity should not be aware of your business logic. I cannot help you more since I don't know which is the goal of that helper, but here you have other alternatives:

ALTERNATIVE 1 (based on your description seems that helper is an stateful bean, so it is not candidate to be a @Service, which I personally think it should be)

@Controller
public MyController {
    @RequestMapping(...)
    public void processRequest() {
        A a = new A();
        ...
        Helper helper = new Helper(a);  // CRepository is successfully autowired
    }
}

@Configurable(autowire = Autowire.BY_TYPE)
public class Helper {
    A a;
    @Autowired
    CRepository repo;
}

@Configuration
@EnableSpringConfigured
public Application {
    ...
}

ALTERNATIVE 2 (make your Helper class stateless so that spring is aware of your beans without the need of extra stuff like @Confgurable/@EnableSpringConfigured)

@Controller
public MyController {
     @Autowired Helper helper;  // CRepository is correctly autowired

    @RequestMapping(...)
    public void processRequest() {
        A a = new A();
        ...
        helper.doSomething(a);
    }
}

@Service
public class Helper {
    // A a;  remove dependency to A to make it stateless
    @Autowired
    CRepository repo;

    public Helper() {
    }

    public void doSomething(A a) {
        ...
        repo.save(a);
    }
}
Community
  • 1
  • 1
ibai
  • 1,143
  • 1
  • 17
  • 28
-1

You cannot autowire nothing in your Helper class because it isn't managed by Spring. You can use this approach:

public class HelperManager {
  @Autowired
  private ApplicationContext context;

  public Helper getHelper(A a) {
    return context.getBean(Helper.class, a);
}

Configure Helper to be a prototype bean:

@Configuration
public class MyConfiguration {
  @Bean
  public HelperManager helperManager() {
    return new HelperManager();
  }

  @Bean
  @Scope("prototype")
  public Helper helper(A a) {
    return new Helper(a);
  }
}

And finally in your controller:

@Controller
public class MyController {
  @Autowired
  private HelperManager helperManager;

  public someMethodWhereToInstanceYourHelper(A a) {
    ...
    Helper helper = helperManager.getHelper(a);
    ...
  }
}
Francesco Pitzalis
  • 2,042
  • 1
  • 16
  • 20