spring-cloud / spring-cloud-connectors

Library to let cloud applications connect to services
Apache License 2.0
185 stars 161 forks source link

Spring Data Rest & MongoMapping Converter #98

Closed jhiemer closed 9 years ago

jhiemer commented 9 years ago

Hi, I recently opened two issues in Spring Data Rest [0], [1], which are a result of a missing configuration of the mappingBasePackages for the mongoMappingContext. I could fix this after a lot debugging, until I found the origin of the problem, with [3]. The question for me here is: is this the kings road or should there be some improvements in Spring Data Rest (@olivergierke) or in the Cloud Connectors.

[0] https://jira.spring.io/browse/DATAREST-442 [1] https://jira.spring.io/browse/DATAREST-443 [3] https://gist.github.com/jhiemer/5f743a85792d58060c8a

odrotbohm commented 9 years ago

So the fundamental issue seems to be that the Spring Cloud Connector documentation strongly suggest to inherit from a base class, which in Johannes' case created an insufficient MongoDB infrastructure setup in turn leading to assumed bugs in Spring Data REST.

After a bit of discussion we came to quite a few observations:

ramnivas commented 9 years ago

A quick comment:

Whenever a user decides to work with AbstractCloudConfiguration she will be required to have both Spring Data MongoDB and Spring Data Redis on the classpath, whether you use MongoDB or Redis or not.

Not really. Even though the class refers to all connector types, all those types have optional dependency. Specifically, an user app won't need to put Spring Data Redis unless it is using Redis. See Spring Sendgrid for example; it doesn't have dependency on Spring Data or Spring AMQP.

jhiemer commented 9 years ago

@ramnivas are you sure about that? If I remember correctly, I had to include the Redis dependencies of Spring, because of a ClassNotFoundException during application startup. The project is using Mongo, RabbitMq and Postgres, so these dependencies were use anyway.

odrotbohm commented 9 years ago

I just did the following:

I get this exception startup:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.2.1.RELEASE)

2015-01-26 09:54:51.163  INFO 35248 --- [           main] demo.ClassLoadingApplication             : Starting ClassLoadingApplication on Serendipity-6.local with PID 35248 (/Users/olivergierke/Documents/workspace/class-loading/target/classes started by olivergierke in /Users/olivergierke/Documents/workspace/class-loading)
2015-01-26 09:54:51.195  INFO 35248 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@480bdb19: startup date [Mon Jan 26 09:54:51 CET 2015]; root of context hierarchy
2015-01-26 09:54:51.223  INFO 35248 --- [           main] .b.l.ClasspathLoggingApplicationListener : Application failed to start with classpath: [file:/Users/olivergierke/Documents/workspace/class-loading/target/classes/, file:/Users/olivergierke/.m2/repository/org/springframework/cloud/spring-cloud-spring-service-connector/1.1.0.RELEASE/spring-cloud-spring-service-connector-1.1.0.RELEASE.jar, file:/Users/olivergierke/.m2/repository/org/springframework/cloud/spring-cloud-core/1.1.0.RELEASE/spring-cloud-core-1.1.0.RELEASE.jar, file:/Users/olivergierke/.m2/repository/org/springframework/spring-context/4.1.4.RELEASE/spring-context-4.1.4.RELEASE.jar, file:/Users/olivergierke/.m2/repository/org/springframework/spring-aop/4.1.4.RELEASE/spring-aop-4.1.4.RELEASE.jar, file:/Users/olivergierke/.m2/repository/aopalliance/aopalliance/1.0/aopalliance-1.0.jar, file:/Users/olivergierke/.m2/repository/org/springframework/spring-beans/4.1.4.RELEASE/spring-beans-4.1.4.RELEASE.jar, file:/Users/olivergierke/.m2/repository/org/springframework/spring-expression/4.1.4.RELEASE/spring-expression-4.1.4.RELEASE.jar, file:/Users/olivergierke/.m2/repository/org/springframework/boot/spring-boot-starter/1.2.1.RELEASE/spring-boot-starter-1.2.1.RELEASE.jar, file:/Users/olivergierke/.m2/repository/org/springframework/boot/spring-boot/1.2.1.RELEASE/spring-boot-1.2.1.RELEASE.jar, file:/Users/olivergierke/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/1.2.1.RELEASE/spring-boot-autoconfigure-1.2.1.RELEASE.jar, file:/Users/olivergierke/.m2/repository/org/springframework/boot/spring-boot-starter-logging/1.2.1.RELEASE/spring-boot-starter-logging-1.2.1.RELEASE.jar, file:/Users/olivergierke/.m2/repository/org/slf4j/jcl-over-slf4j/1.7.8/jcl-over-slf4j-1.7.8.jar, file:/Users/olivergierke/.m2/repository/org/slf4j/slf4j-api/1.7.8/slf4j-api-1.7.8.jar, file:/Users/olivergierke/.m2/repository/org/slf4j/jul-to-slf4j/1.7.8/jul-to-slf4j-1.7.8.jar, file:/Users/olivergierke/.m2/repository/org/slf4j/log4j-over-slf4j/1.7.8/log4j-over-slf4j-1.7.8.jar, file:/Users/olivergierke/.m2/repository/ch/qos/logback/logback-classic/1.1.2/logback-classic-1.1.2.jar, file:/Users/olivergierke/.m2/repository/ch/qos/logback/logback-core/1.1.2/logback-core-1.1.2.jar, file:/Users/olivergierke/.m2/repository/org/springframework/spring-core/4.1.4.RELEASE/spring-core-4.1.4.RELEASE.jar, file:/Users/olivergierke/.m2/repository/org/yaml/snakeyaml/1.14/snakeyaml-1.14.jar]
2015-01-26 09:54:51.231 ERROR 35248 --- [           main] o.s.boot.SpringApplication               : Application startup failed

java.lang.NoClassDefFoundError: org/springframework/data/mongodb/MongoDbFactory
    at java.lang.Class.getDeclaredMethods0(Native Method)
    at java.lang.Class.privateGetDeclaredMethods(Class.java:2688)
    at java.lang.Class.getDeclaredMethods(Class.java:1962)
    at org.springframework.core.type.StandardAnnotationMetadata.hasAnnotatedMethods(StandardAnnotationMetadata.java:129)
    at org.springframework.context.annotation.ConfigurationClassUtils.isLiteConfigurationCandidate(ConfigurationClassUtils.java:157)
    at org.springframework.context.annotation.ConfigurationClassUtils.isConfigurationCandidate(ConfigurationClassUtils.java:125)
    at org.springframework.context.annotation.ConfigurationClassParser.processMemberClasses(ConfigurationClassParser.java:312)
    at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:243)
    at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:226)
    at org.springframework.context.annotation.ConfigurationClassParser.processMemberClasses(ConfigurationClassParser.java:314)
    at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:243)
    at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:226)
    at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:193)
    at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:163)
    at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:306)
    at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:239)
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:254)
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:94)
    at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:606)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:462)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:691)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:321)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:961)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:950)
    at demo.ClassLoadingApplication.main(ClassLoadingApplication.java:17)
Caused by: java.lang.ClassNotFoundException: org.springframework.data.mongodb.MongoDbFactory
    at java.net.URLClassLoader$1.run(URLClassLoader.java:372)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 25 common frames omitted

If I add MongoDB, the exception changes to complain about Spring AMQP's ConnectionFactory missing. So it's not really the JVM causing the issue but Spring trying to analyze the configuration class.

Could it be that the issue just doesn't appear on CF environments as it implicitly has the relevant libraries on the classpath anyway?

jhiemer commented 9 years ago

Exactly the same I had with Redis support.

ramnivas commented 9 years ago

Which JDK version are you using? I have been reported some sighting of this issue with specific version(s) of JDK (older version of Java 8), but could never reproduce with the latest. It could be how eagerly each JDK's classloader demands types. In fact the reason for AbstractCloudConfig containing ServiceConnectionFactory and thus requiring users to to use connectionFactory().mongoDbFactory() instead of a more convenient mongoDbFactory() is Spring's proxy creation required me to add an extra level of indirection to avoid loading classes other than that app needs.

Could one of you try to compile Spring Music and Spring Sendgrid? I had discussed an alternative possibilities with @scottfrederick should the issue arise again. So knowing a reproducible project + JDK version will help.

scottfrederick commented 9 years ago

See #88

jhiemer commented 9 years ago

Newly deployed application java.lang.NoClassDefFoundError: org/springframework/amqp/rabbit/connection/ConnectionFactory this is definitely an issue.

jghiloni commented 9 years ago

I'm also seeing this with Oracle JDK 1.8.0_25 and spring-cloud 1.0.0.RELEASE.

scottfrederick commented 9 years ago

Closing this as the resolution is a duplicate of #88.