1

I have some java objects coming from external library which I need to inject in my spring project. Problem is the classes from library is not aware of any spring api's

If I inject the beans from library to Service using @Autowired I am getting org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type

Following is my service class

@Path("/test")
public class TestService {

    @Autowired
    SomeOtherClass service;

    @GET
    public Response get(){
        return Response.ok(service.someMethod()).build();
    }
}

and following is my class from library which is not aware of spring

public class SomeOtherClass {

    public String someMethod(){
        return "Data from library";
    }
}

When I invoke my service I get exception as

org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.SomeOtherClass' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

Is there are way in spring to inject a plain Java Object similar to that of injection in **CDI**? There is one option to define applicationcontext.xml and define SomeOtherClass in xml and use getBean, but I don't want to do that. Is there any other option?

Note:

Following options cannot be considered because I have100's of classes coming from library

  1. Cannot use applicationcontext.xml

  2. Cannot @Configuration @Bean to produce beans.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Surendran Duraisamy
  • 2,431
  • 5
  • 26
  • 29
  • 1
    You don't need `getBean` you just need to declare an instance of `SomeOtherClass` then `@Autowired` will work. Spring will only inject managed beans (just like CDI if something isn't a managed bean it won't inject anything either). – M. Deinum Jan 02 '17 at 08:33
  • 1
    Then don't use spring... You need to make those classes known to be spring managed instances, if you don't it will not work. If you cannot (or will not) use xml or java based configuration there isn't much that spring can do to help. (Although you could extend spring to detect/scan for those classes but that would require some knowledge on the internals and working of spring). – M. Deinum Jan 02 '17 at 09:53

3 Answers3

4

You could use the @Configuration and @Bean annotations as follows -

Create a new class:

@Configuration
public class AppConfig {

    @Bean
    SomeOtherClass someOtherClassBean(){ return new SomeOtherClass();}

}

Now the auto wiring shall work. What it does, is actually creating a bean and letting Spring know about it.

galusben
  • 5,948
  • 6
  • 33
  • 52
1

Maybe try adding the beans programatically to the IoC container: Add Bean Programmatically to Spring Web App Context

You need to find all the classes you want to instantiate and use one of the methods in the linked question.

Community
  • 1
  • 1
galusben
  • 5,948
  • 6
  • 33
  • 52
  • writing extra code to achieve the injection is similar to having context file or bean configuration. I am looking for some out of box support similar to bean-discovery-mode="ALL" in java ee – Surendran Duraisamy Jan 02 '17 at 10:40
  • 1
    I am not sure there is something like that, it even makes sense (to me) that there isn't. Seems to me that in most use cases it makes sense to control what goes into the IoC container. Hope you'll find something useful. Let us know :-) – galusben Jan 02 '17 at 12:30
1

You can use reflection to add Bean definitions programatically.

    @Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
    Reflections ref = new Reflections(new ConfigurationBuilder()
            .setScanners(new SubTypesScanner(false /* don't exclude Object.class */), new ResourcesScanner())
            .setUrls(ClasspathHelper.forPackage(PACKAGE_NAME))
            .filterInputsBy(new FilterBuilder().include(FilterBuilder.prefix(PACKAGE_NAME))));
    ref.getSubTypesOf(Object.class).stream()
            .forEach(clazz -> {
                logger.info("Defining pojo bean: {} -> {}", Introspector.decapitalize(clazz.getSimpleName()), clazz.getCanonicalName());
                registry.registerBeanDefinition(Introspector.decapitalize(clazz.getSimpleName()),
                        BeanDefinitionBuilder.genericBeanDefinition(clazz).getBeanDefinition());
            });
}

Subsequently, these beans can be @Autowired elsewhere. See Gist: https://gist.github.com/ftahmed/a7dcdbadb8bb7dba31ade463746afd04

ftahmed
  • 104
  • 2