1

I am struggling to get my spring-boot application as a dependency to another java (non-spring) application.

I was asked to develop a new REST API with a few methods and an access to an Oracle database. I used Spring-boot for this, and the application on its own or deployed on a server is working well. After a few tweaks, I got this divided into a few modules as follows:

  • models : contains the model objects of the business code
  • api : contains the business code and the actual API
    • has a dependency on model
    • contains all the properties necessary to connect to the database
  • ws: this part can be deployed on a server, it enables the REST API, I used: https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#build-tool-plugins-maven-packaging for reference
  • starter : contains the spring-boot harness
    • has a dependency on api
    • it loads the properties from api using @propertySource annotation
    • has a dependency on ws
    • I am able to start the application if I run the main class (as expected)

I am now trying to give access to the api module from another java application (non-spring), and took inspiration from this post: https://objectpartners.com/2010/08/23/gaining-access-to-the-spring-context-in-non-spring-managed-classes/ to gain access to the applicationContext of the API and came up with this:

API/application-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:context="http://www.springframework.org/schema/context"
   xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans.xsd 
http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan  base-package="be.belga.mediaservice"/>
    <context:annotation-config />
</beans>

API/SpringContext.java

@Component
@EnableJpaRepositories("be.belga.mediaservice.dao")
public class SpringContext {

private SpringContext() {}


private static class ApplicationContextHolder {
    private static ApplicationContext instance = new ClassPathXmlApplicationContext("application-context.xml");
}

public static ApplicationContext getInstance() {
    return ApplicationContextHolder.instance;
}
}

with that method, I am able to load the API doing this:

MediaServiceAPI mediaServiceAPI = (MediaServiceAPI) 
SpringContext.getInstance().getBean("mediaServiceAPI");

but I get an Exception:

Exception in thread "main" java.lang.ExceptionInInitializerError
at be.belga.mediaservice.util.SpringContext.getInstance(SpringContext.java:20)
at Test.main(Test.java:10)
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'mediaValueServiceImpl' defined in URL [jar:file:/home/mike/.m2/repository/be/belga/mediaservice-api/0.1.7/mediaservice-api-0.1.7.jar!/be/belga/mediaservice/service/impl/MediaValueServiceImpl.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'socialMediaServiceImpl' defined in URL [jar:file:/home/mike/.m2/repository/be/belga/mediaservice-api/0.1.7/mediaservice-api-0.1.7.jar!/be/belga/mediaservice/service/impl/SocialMediaServiceImpl.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'socialMetricsRepository': Cannot create inner bean '(inner bean)#5afa3c9' of type [org.springframework.orm.jpa.SharedEntityManagerCreator] while setting bean property 'entityManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#5afa3c9': Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:749)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:189)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1193)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1095)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:513)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
13:39:04.731 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Retrieved dependent beans for bean '(inner bean)#7ef82753': [socialMetricsRepository]
13:39:04.731 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Retrieved dependent beans for bean '(inner bean)#202b0582': [(inner bean)#7ef82753]
13:39:04.732 [main] WARN org.springframework.context.support.ClassPathXmlApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'mediaValueServiceImpl' defined in URL [jar:file:/home/mike/.m2/repository/be/belga/mediaservice-api/0.1.7/mediaservice-api-0.1.7.jar!/be/belga/mediaservice/service/impl/MediaValueServiceImpl.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'socialMediaServiceImpl' defined in URL [jar:file:/home/mike/.m2/repository/be/belga/mediaservice-api/0.1.7/mediaservice-api-0.1.7.jar!/be/belga/mediaservice/service/impl/SocialMediaServiceImpl.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'socialMetricsRepository': Cannot create inner bean '(inner bean)#5afa3c9' of type [org.springframework.orm.jpa.SharedEntityManagerCreator] while setting bean property 'entityManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#5afa3c9': Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available
13:39:04.732 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1283bb96: defining beans [mediaValueForPressCommand,mediaValueServiceImpl,socialMediaServiceImpl,mediaReachScoreServiceImpl,XMLUtil,springContext,mediaServiceAPI,twitterSocialMediaServiceFacadeImpl,youtubeRestSocialMediaServiceFacadeImpl,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalPersistenceAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,org.springframework.data.jpa.repository.config.JpaRepositoryConfigExtension#0,emBeanDefinitionRegistrarPostProcessor,jpaMappingContext,jpaContext,agenciesMetricsRepository,CIMMetricsRepository,systemMetricsRepository,socialMetricsRepository,serviceTypeValueRepository,keywordsRepository]; root of factory hierarchy
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at be.belga.mediaservice.util.SpringContext$ApplicationContextHolder.<clinit>(SpringContext.java:16)
... 2 more
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'socialMediaServiceImpl' defined in URL [jar:file:/home/mike/.m2/repository/be/belga/mediaservice-api/0.1.7/mediaservice-api-0.1.7.jar!/be/belga/mediaservice/service/impl/SocialMediaServiceImpl.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'socialMetricsRepository': Cannot create inner bean '(inner bean)#5afa3c9' of type [org.springframework.orm.jpa.SharedEntityManagerCreator] while setting bean property 'entityManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#5afa3c9': Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:749)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:189)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1193)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1095)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:513)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:208)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1138)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:835)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:741)
... 17 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'socialMetricsRepository': Cannot create inner bean '(inner bean)#5afa3c9' of type [org.springframework.orm.jpa.SharedEntityManagerCreator] while setting bean property 'entityManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#5afa3c9': Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:313)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:129)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1531)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1276)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:208)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1138)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:835)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:741)
... 31 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#5afa3c9': Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:359)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:108)
at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:634)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:448)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1173)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1067)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:513)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:299)
... 45 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:687)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1207)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:284)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:351)
... 53 more

Is there a way to actually use the API part of my app as a dependency to the other java application?

  • PDO : https://stackoverflow.com/questions/47503046/error-creating-bean-with-name-entitymanagerfactory-when-add-spring-boot-jpa-de/47504698#47504698 – Mehraj Malik Feb 19 '18 at 12:16
  • @MehrajMalik thanks for your comment, I edited my question and posted the complete stacktrace – Michael Desmedt Feb 19 '18 at 12:48
  • Full stack trace isn't helpful in this case as the error is clear: a dependency named entityManagerFactory is not available. – SteveD Feb 19 '18 at 12:49
  • Spring Boot is doing a lot of automatic bean creation and wiring which isn't done if you manually create a Spring Context. – SteveD Feb 19 '18 at 12:51
  • Your order of dependencies looks weird to me. Why does starter depend on ws (which you say is a WAR)? When you build the WAR for deployment, the main class from starter is added to the WAR? – SteveD Feb 19 '18 at 22:15

1 Answers1

0

Your core APIs, models and implementations shouldn't have dependencies on the Spring container, in which case they are freely usable by any other Java application, as long as it can provide all needed dependencies.

You might think, "OK, but how does that help me?". We need to find out more before coming up with a solution that works.

When you say you've split things up into modules, you mean a separate JAR for the models, APIs and REST stuff?

These JARs should be directly usable as dependencies of the other application. There should be no need for the other application to use Spring (unless they are already using Spring).

SteveD
  • 5,396
  • 24
  • 33
  • yes that's it. I have 1 jar per module, except the WS which is a war archive that can be deployed. From my non-spring app, I can of course add the API module as dependency in my POM and 'see' the class I'm interested in. Howerver, this fails because the spring(boot ?) dependencies are not satisfied. I then get a NullPointerException. my aim is to access the API I developed as a dependency in my non-spring app. Does that make sense ? – Michael Desmedt Feb 19 '18 at 14:34
  • What Spring dependencies do your API & model JARs have? I try to avoid my core functionality depending on anything from Spring so I can use them in non-Spring apps. – SteveD Feb 19 '18 at 22:17