Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exception on startup due to telemetry dependencies on modules removed from Java 11 #598

Closed
rupert-madden-abbott opened this issue Feb 24, 2019 · 5 comments

Comments

@rupert-madden-abbott
Copy link

rupert-madden-abbott commented Feb 24, 2019

Environment

  • Spring boot starter: active directory spring boot starter
  • OS Type: Windows
  • Java version: 1.11
  • Starter version: 2.1.4
  • Spring boot version: 2.1.3.RELEASE

Summary

On startup, the following exception is thrown when running with the Spring Boot Maven Plugin:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'telemetryProxy' defined in class path resource [com/microsoft/azure/telemetry/TelemetryProxyConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.microsoft.azure.telemetry.TelemetryProxy]: Factory method 'telemetryProxy' threw exception; nested exception is java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException
	at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:627) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:607) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1305) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1144) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:849) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:877) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:142) ~[spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE]
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775) ~[spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE]
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) ~[spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:316) ~[spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260) ~[spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248) ~[spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE]
	at com.github.rupert654.adstarterclassscanningbug.Application.main(Application.java:9) ~[classes/:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
	at org.springframework.boot.maven.AbstractRunMojo$LaunchRunner.run(AbstractRunMojo.java:558) ~[na:na]
	at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na]
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.microsoft.azure.telemetry.TelemetryProxy]: Factory method 'telemetryProxy' threw exception; nested exception is java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:622) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	... 25 common frames omitted
Caused by: java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException
	at com.microsoft.applicationinsights.internal.config.TelemetryConfigurationFactory.<init>(TelemetryConfigurationFactory.java:90) ~[applicationinsights-core-2.2.0.jar:na]
	at com.microsoft.applicationinsights.internal.config.TelemetryConfigurationFactory.<clinit>(TelemetryConfigurationFactory.java:66) ~[applicationinsights-core-2.2.0.jar:na]
	at com.microsoft.applicationinsights.TelemetryConfiguration.getActive(TelemetryConfiguration.java:70) ~[applicationinsights-core-2.2.0.jar:na]
	at com.microsoft.applicationinsights.TelemetryClient.<init>(TelemetryClient.java:83) ~[applicationinsights-core-2.2.0.jar:na]
	at com.microsoft.azure.telemetry.TelemetryProxy.getTelemetryClient(TelemetryProxy.java:34) ~[azure-spring-boot-2.1.4.jar:na]
	at com.microsoft.azure.telemetry.TelemetryProxy.<init>(TelemetryProxy.java:25) ~[azure-spring-boot-2.1.4.jar:na]
	at com.microsoft.azure.telemetry.TelemetryProxyConfiguration.telemetryProxy(TelemetryProxyConfiguration.java:20) ~[azure-spring-boot-2.1.4.jar:na]
	at com.microsoft.azure.telemetry.TelemetryProxyConfiguration$$EnhancerBySpringCGLIB$$5e0b129c.CGLIB$telemetryProxy$0(<generated>) ~[azure-spring-boot-2.1.4.jar:na]
	at com.microsoft.azure.telemetry.TelemetryProxyConfiguration$$EnhancerBySpringCGLIB$$5e0b129c$$FastClassBySpringCGLIB$$f0295746.invoke(<generated>) ~[azure-spring-boot-2.1.4.jar:na]
	at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244) ~[spring-core-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:363) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at com.microsoft.azure.telemetry.TelemetryProxyConfiguration$$EnhancerBySpringCGLIB$$5e0b129c.telemetryProxy(<generated>) ~[azure-spring-boot-2.1.4.jar:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	... 26 common frames omitted
Caused by: java.lang.ClassNotFoundException: javax.xml.bind.JAXBException
	at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:471) ~[na:na]
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:588) ~[na:na]
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521) ~[na:na]
	... 43 common frames omitted

Reproduce steps

I've created a sample repository to reproduce the bug.

  1. Ensure JAVA_HOME is set to JDK 11 so that it is used by Maven.
  2. Checkout the repository
  3. Execute mvn spring-boot:run

Please note that I have disabled telemetry using the property:

azure.activedirectory.allow-telemetry=false

Expected Results

To not see that exception.

Actual Results

The above exception occurs in the startup logs.

Workaround

Adding back these Java APIs (removed in Java 11) fixed the problem.

    <dependency>
      <groupId>org.glassfish.jaxb</groupId>
      <artifactId>jaxb-runtime</artifactId>
    </dependency>

Recommendations

The root cause of this problem is microsoft/ApplicationInsights-Java#674.

As far as I can work out, this dependency is pulled in purely to enable telemetry. That's fine but I've got it disabled and it's still breaking my application!

In your README, you say:

Microsoft would like to collect data about how users use this Spring boot starter. Microsoft uses this information to improve our tooling experience. Participation is voluntary.

The core problem here is this telemetry feature:

  • Pulls in a ton of Maven dependencies that are irrelevant to the core function of this starter
  • Executes a bunch of Spring auto-configuration that is irrelevant to the core function of this starter
  • Does both of these things even if telemetry has been explicitly disabled.

Can I please ask that you offer a more robust solution to disabling the telemetry?

Firstly, if you just had a single property to disable telemetry, instead of one per starter, then you could place a condition on all auto-configuration relating to Telemetry e.g. TelemetryProxyConfiguration. This would at least ensure that no code relating to Telemetry ran which could otherwise cause errors (like this one) even though it had been disabled.

Secondly, you could package up all the telemetry code into its own library, and place any dependencies relating to telemetry (like application-insights) into that library. This would make opting out of everything much easier, as consumers could just exclude that library in Maven e.g. something like this:

<dependency>
  <groupId>com.microsoft.azure</groupId>
  <artifactId>azure-active-directory-spring-boot-starter</artifactId>
  <version>2.1.4</version>
  <exclusions>
    <exclusion>
      <groupId>com.microsoft.azure</groupId>
      <artifactId>telemetry</artifactId>
    </exclusion>
  </exclusions>
</dependency>

Currently, I can't even exclude applicationinsights-core in Maven and TelemetryProxyConfiguration in Spring because AADOAuth2AutoConfiguration has a dependency on TelemetryProxy regardless of whether telemetry has been disabled.

@rupert-madden-abbott rupert-madden-abbott changed the title Exception on startup due to dependencies on modules removed from Java 11 Exception on startup due to telemetry dependencies on modules removed from Java 11 Feb 24, 2019
@dhaval24
Copy link
Contributor

@rupert654 how about you reference jaxb in your application? Would that help as workaround. Currently with java 11 it removes jaxb from the core java platform and Application Insights SDK depends on that.

Ideally, @Incarnation-p-lee I agree with @rupert654 that you should have single property to disable telemetry for all azure starters.

@rupert-madden-abbott
Copy link
Author

Hi @dhaval24,

That does indeed work as a workaround (I mention the library that Spring Boot recommends in the issue above).

However, it has more consequences. This particular library, and indeed another dependency pulled in by applicationinsights-core (grpc-netty-shaded), are fat jars which cause errors when running on Tomcat and using JSPs because Tomcat's class path scanning break on shaded jars. I then have to do more work (not much but more), to fix this new issue.

That isn't really the fault of this library, but the real issue here is this library pulls in a lot of complexity to do something that is not a core part of its function and disabling it does not properly disable it. I could fork this library, remove the telemetry and it would provide a better experience for developers. It's one thing to include opt-out tracking but its another for your opt-out tracking to then break your own library (or ask developers to jump through hoops to stop it from breaking).

A much cleaner solution would be to be able to exclude a Maven package, which would automatically remove all the relevant auto-configuration and unneeded dependencies. I'm happy to raise a PR if this approach is acceptable?

@dhaval24
Copy link
Contributor

dhaval24 commented Mar 6, 2019

@rupert654 yes, I agree that Application Insights, is complex sdk and is used for monitoring applications. In general it is a good practice to reduce the dependencies in the library to avoid classpath hells.

@Incarnation-p-lee can comment more, but I believe there was some conversation that in future this dependency would be removed and the azure-spring-starters will rely on application insights rest api as the purpose right now is to just collect Business telemetry.

@Incarnation-p-lee
Copy link
Contributor

@rupert654 Could you please have a try from our newest release version ? Thanks a lot.

@rupert-madden-abbott
Copy link
Author

@Incarnation-p-lee I've just tested on 2.1.6 and this all seems to be fixed. Thanks very much! My jars are much lighter now!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants