Spring Bean implemented by a 3rd party library that uses @Inject conflicting with Spring's injection mechanism

馋奶兔 提交于 2020-01-06 05:25:46

问题


I am trying to have a @Bean implemented by a class from a 3rd party library (OWL API).

This implementation uses an @Inject annotation. Spring tries to interpret it, interfering with the injection mechanism of the 3rd party library and avoiding it to work as intended.

Is there a way to instruct Spring to ignore the @Inject annotations of the bean implementation, when instantiating the bean?

I found few questions about this subject but none of them provided a solution usable in my context.

I actually managed to resolve the issue myself, by wrapping the 3rd party object in an anonymous class, apparently creating a barrier for Spring and preventing it to look into this object (see the point 3. below), but I consider it to be an ugly workaround.

Details:

According to the OWL API documentation, the OWLOntologyManager is to be created like this:

OWLOntologyManagerFactory ontologyManagerFactory = new OWLManager();
OWLOntologyManager owlOntologyManager = ontologyManagerFactory.get();
//... use owlOntologyManager

Indeed, in my Spring application that was working. However, I need to have the OWLOntologyManagerFactory with an application scope and OWLOntologyManager with a Session scope.

So I declared each of these two objects as a Spring @Bean, with an appropriate scope and started to receive an error:

Error creating bean with name 'scopedTarget.sessionOWLOntologyManager': Unsatisfied dependency expressed through method 'setIRIMappers' parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'java.util.Set' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

See below samples of the code.

  1. Functional first test of the code, not meeting the application needs:
@RestController
public class OntologiesController {
    @RequestMapping("ontologies")
    public String manager_loadOntology(
        @RequestParam(value="ontologyIriString") String ontologyIriString
    ) throws OWLOntologyCreationException
    {
        OWLOntologyManagerFactory ontologyManagerFactory = new OWLManager();
        OWLOntologyManager owlOntologyManager = ontologyManagerFactory.get();
        OWLOntology ontology = owlOntologyManager.loadOntology(IRI.create(ontologyIriString));
        return ontology.toString();
    }
}
  1. Not functional code failing to create OWLOntologyManager with the error quoted above.
@Configuration
public class ApplicationScopeConfig {
    @Bean
    @ApplicationScope
    public OWLOntologyManagerFactory applicationOWLOntologyManagerFactory() {
        return new OWLManager();
    }
}
@Configuration
public class SessionScopeConfig {
    @Autowired
    OWLOntologyManagerFactory applicationOWLOntologyManagerFactory;
    @Bean
    @SessionScope
    public OWLOntologyManager sessionOWLOntologyManager() {
        return applicationOWLOntologyManagerFactory.get();
    }
}
@RestController
public class OntologiesController {
    @Autowired
    private OWLOntologyManager sessionOWLOntologyManager;
    @RequestMapping("ontologies")
    public String manager_loadOntology(
            @RequestParam(value="ontologyIriString") String ontologyIriString
    ) throws OWLOntologyCreationException
    {
        OWLOntology ontology = sessionOWLOntologyManager.loadOntology(IRI.create(ontologyIriString));
        return ontology.toString();
    }
}
  1. Functional code, working as needed, but ugly, is there a way to improve it?

In the code from the point 2 I modified the sessionOWLOntologyManager() as follows, wrapping it to an anonymous class that prevents Spring to look into the real owlOntologyManager.

@Bean
@SessionScope
public OWLOntologyManager sessionOWLOntologyManager() {
    final OWLOntologyManager owlOntologyManager = applicationOWLOntologyManagerFactory.get();
    return new OWLOntologyManager() {
        public void clearOntologies() {
            owlOntologyManager.clearOntologies();
        }
        //additional 400 lines implementing all methods by delegating to owlOntologyManager
        //Apparently that creates a barrier for Spring so it does not conflict with the
        //@Inject annotation in the implementation of the original owlOntologyManager,
        //but in spite of having IDE support to generate this delegation, I consider it
        //as an workaround.
    }
}

回答1:


As it eventually turns out that this is related to Configuring Spring to ignore dependencies annotated with @Inject, so I assume that a chance to get better answers is low and I post my additional findings in a reply to myself.

  1. The class responsible for recognizing the @Inject is org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor. With my Spring knowledge I was however not able to intercept its behavior. The class SpringBeanAutowiringInterceptor, mentioned in the related question, does not exist in Spring 5.

  2. For now I go with an improvement to my solution in the point 3. Instead of generating dozens of delegating methods (it can be done automatically by IDE), I go with the code below, using the reflection. The advantage is that it will be more resistant to changes if I should upgrade the OWLAPI library one day. Also it has significantly less lines. I assume that the reflection might be less performant.

@Bean
@SessionScope
public OWLOntologyManager sessionOWLOntologyManager() {

    final OWLOntologyManager owlOntologyManager = applicationOWLOntologyManagerFactory.get();

    //Instead of returning owlOntologyManager directly,
    //the delegating proxy prevents Spring to resolve @Inject annotations
    //in the implementation of owlOntologyManager.

    return (OWLOntologyManager)Proxy.newProxyInstance(
            owlOntologyManager.getClass().getClassLoader(),
            owlOntologyManager.getClass().getInterfaces(),
            (o, method, args) ->
                method.invoke(owlOntologyManager, args)
        );
}


来源:https://stackoverflow.com/questions/59582720/spring-bean-implemented-by-a-3rd-party-library-that-uses-inject-conflicting-wit

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!