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

Spring and Spring boot support #22

Closed
arturhg opened this issue Oct 19, 2018 · 8 comments
Closed

Spring and Spring boot support #22

arturhg opened this issue Oct 19, 2018 · 8 comments
Labels

Comments

@arturhg
Copy link

arturhg commented Oct 19, 2018

Is it possible to use Manifold with Spring and Spring Boot projects?
I tried Manifold with Spring Boot 1.x and it crashed with different exceptions each time.
Probably should try again and post trace here.
Thank you.

@rsmckinney
Copy link
Member

rsmckinney commented Oct 19, 2018

Hi arturhg.

Thanks for the report!

Quick answer. YES. It is possible to use Manifold with Spring.

I've generated a demo Spring app using spring initializr, added Manifold dependency, and a simple use-case. I can reproduce an exception (attached to this post) with a call to SpringApplication.run().

Update:

Good news! After further inspection the exception from Spring is actually just a scary warning logged to the console, it does not interrupt normal execution, therefore nothing to be concerned about. In any case, you can use the workaround documented in this post to avoid the warning.

Based on the stack trace it appears Spring scans the classpath of the application's URLClassLoader and assumes all the URLs are files. Unfortunately, they may not all be files because Manifold adds a special URL to the class loader with the "manifoldclass" protocol. In my view Spring should simply skip URLs that are not files instead of allowing the exception to fall through -- there is no harm in skipping a URL it can't handle. Perhaps I'll add a pull request to fix this.

Fortunately, you can avoid this problem in a number of different ways, depending on your needs. The easiest fix is to simply add the @NoBootstrap annotation to the main class e.g.,

@SpringBootApplication
@NoBootstrap
public class DemoApplication {

This tell Manifold not to generate a class initializer to bootstrap Manifold at runtime. Instead another class that has the initializer will do it. However, if your main class requires runtime features you'll have to bootstrap manually before the runtime is needed. Doing this involves adding a simple call wherever you need it:

Bootstrap.init();

Features that require Manifold runtime include:

  • Structural typing mainly because proxies are generated dynamically at runtime
  • JSON support because it is built using structural types
  • Dark Java because it compiles and loads Java dynamically
  • dynamic option to Manifold javac pluign because it turns off static compilation in favor of dynamic compilation

Let me know if this helps.

There are other ways to work around the exception. I'll document them and push the Spring sample app to github for future reference.

Let me know if you have additional questions or issues.

Thanks again for the report!

Scott

Exception: (note this exception is merely logged, it does not stop normal execution of your application)

java.io.FileNotFoundException: URL [manifoldclass://414493378/com/example/demo/] cannot be resolved to absolute file path because it does not reside in the file system: manifoldclass://414493378/com/example/demo/
	at org.springframework.util.ResourceUtils.getFile(ResourceUtils.java:217) ~[spring-core-5.0.10.RELEASE.jar:5.0.10.RELEASE]
	at org.springframework.core.io.AbstractFileResolvingResource.getFile(AbstractFileResolvingResource.java:131) ~[spring-core-5.0.10.RELEASE.jar:5.0.10.RELEASE]
	at org.springframework.core.io.UrlResource.getFile(UrlResource.java:225) ~[spring-core-5.0.10.RELEASE.jar:5.0.10.RELEASE]
	at org.springframework.core.io.support.PathMatchingResourcePatternResolver.doFindPathMatchingFileResources(PathMatchingResourcePatternResolver.java:697) [spring-core-5.0.10.RELEASE.jar:5.0.10.RELEASE]
	at org.springframework.core.io.support.PathMatchingResourcePatternResolver.findPathMatchingResources(PathMatchingResourcePatternResolver.java:510) [spring-core-5.0.10.RELEASE.jar:5.0.10.RELEASE]
	at org.springframework.core.io.support.PathMatchingResourcePatternResolver.getResources(PathMatchingResourcePatternResolver.java:282) [spring-core-5.0.10.RELEASE.jar:5.0.10.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.getResources(AbstractApplicationContext.java:1307) [spring-context-5.0.10.RELEASE.jar:5.0.10.RELEASE]
	at org.springframework.context.support.GenericApplicationContext.getResources(GenericApplicationContext.java:233) [spring-context-5.0.10.RELEASE.jar:5.0.10.RELEASE]
	at org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.scanCandidateComponents(ClassPathScanningCandidateComponentProvider.java:421) [spring-context-5.0.10.RELEASE.jar:5.0.10.RELEASE]
	at org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.findCandidateComponents(ClassPathScanningCandidateComponentProvider.java:316) [spring-context-5.0.10.RELEASE.jar:5.0.10.RELEASE]
	at org.springframework.context.annotation.ClassPathBeanDefinitionScanner.doScan(ClassPathBeanDefinitionScanner.java:275) [spring-context-5.0.10.RELEASE.jar:5.0.10.RELEASE]
	at org.springframework.context.annotation.ComponentScanAnnotationParser.parse(ComponentScanAnnotationParser.java:132) [spring-context-5.0.10.RELEASE.jar:5.0.10.RELEASE]
	at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:288) [spring-context-5.0.10.RELEASE.jar:5.0.10.RELEASE]
	at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:245) [spring-context-5.0.10.RELEASE.jar:5.0.10.RELEASE]
	at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:202) [spring-context-5.0.10.RELEASE.jar:5.0.10.RELEASE]
	at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:170) [spring-context-5.0.10.RELEASE.jar:5.0.10.RELEASE]
	at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:316) [spring-context-5.0.10.RELEASE.jar:5.0.10.RELEASE]
	at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:233) [spring-context-5.0.10.RELEASE.jar:5.0.10.RELEASE]
	at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:271) [spring-context-5.0.10.RELEASE.jar:5.0.10.RELEASE]
	at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:91) [spring-context-5.0.10.RELEASE.jar:5.0.10.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:692) [spring-context-5.0.10.RELEASE.jar:5.0.10.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:530) [spring-context-5.0.10.RELEASE.jar:5.0.10.RELEASE]
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) [spring-boot-2.0.6.RELEASE.jar:2.0.6.RELEASE]
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:386) [spring-boot-2.0.6.RELEASE.jar:2.0.6.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:307) [spring-boot-2.0.6.RELEASE.jar:2.0.6.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1242) [spring-boot-2.0.6.RELEASE.jar:2.0.6.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1230) [spring-boot-2.0.6.RELEASE.jar:2.0.6.RELEASE]
	at com.example.demo.DemoApplication.main(DemoApplication.java:11) [classes/:na]

@arturhg
Copy link
Author

arturhg commented Oct 23, 2018

Amazing answer, rsmckinney!
Will try very soon.

@rsmckinney
Copy link
Member

Update

I logged https://jira.spring.io/browse/SPR-17417, which is now fixed :)

@arturhg
Copy link
Author

arturhg commented Nov 9, 2018

Thank you so much, rsmckinney!
I started trying and will share the updates.

@rsmckinney rsmckinney added the bug label Nov 11, 2018
@arturhg
Copy link
Author

arturhg commented Nov 12, 2018

It works! Thanks a lot.

@marksto
Copy link

marksto commented Apr 7, 2019

Hi @rsmckinney!

You promised once...

I'll document them and push the Spring sample app to github for future reference.

... So where can one find this aforementioned template? =)

@rsmckinney
Copy link
Member

Hi @marksto. Lol, that was a while ago. As I recall after the bug in Spring was fixed to eliminate the warning message I realized there wasn't anything special to do -- you can simply add Manifold dependencies to existing Spring-based projects. Here is the POM file from the app used:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.example</groupId>
	<artifactId>demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>demo</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>systems.manifold</groupId>
			<artifactId>manifold-all</artifactId>
			<version>0.59-alpha</version>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>

			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.8.0</version>
				<configuration>
					<encoding>UTF-8</encoding>
					<compilerArgs>

						<!--Add the Manifold plugin, with string templates and checked exception suppression enabled-->
						<arg>-Xplugin:Manifold strings exceptions</arg>

					</compilerArgs>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

Let me know if you're having trouble using Manifold with a Spring app.

Cheers.

@keshwanramlu
Copy link

I am building a jar from spring boot application that uses manifold for dynamic json 2 java. and get the following error only for jar execution but runs fine on IntelliJ.
java.lang.NullPointerException: Cannot invoke "manifold.rt.api.util.Pair.getFirst()" because "classSymbol" is null
at manifold.ext.DynamicProxyFactory.hasCallHandlerFromExtension(DynamicProxyFactory.java:117) ~[manifold-ext-2024.1.25.jar!/:2024.1.25]
at manifold.ext.DynamicProxyFactory.hasCallHandlerMethod(DynamicProxyFactory.java:102) ~[manifold-ext-2024.1.25.jar!/:2024.1.25]
at manifold.ext.DynamicProxyFactory.makeProxyFactory(DynamicProxyFactory.java:52) ~[manifold-ext-2024.1.25.jar!/:2024.1.25]
at manifold.ext.rt.RuntimeMethods.createProxy(RuntimeMethods.java:415) ~[manifold-ext-rt-2024.1.25.jar!/:2024.1.25]
at manifold.ext.rt.RuntimeMethods.createNewProxy(RuntimeMethods.java:387) ~[manifold-ext-rt-2024.1.25.jar!/:2024.1.25]
at manifold.ext.rt.RuntimeMethods.constructProxy(RuntimeMethods.java:63) ~[manifold-ext-rt-2024.1.25.jar!/:2024.1.25]
at org.sampler.algorithm.Algorithm.getPillarToJourneyMapping(Algorithm.java:169) ~[!/:0.0.1-SNAPSHOT]
at org.sampler.algorithm.Algorithm.getPathwayForPersona(Algorithm.java:63) ~[!/:0.0.1-SNAPSHOT]
at org.sampler.algorithm.Application.run(Application.java:185) ~[!/:0.0.1-SNAPSHOT]
at org.springframework.boot.SpringApplication.lambda$callRunner$5(SpringApplication.java:790) ~[spring-boot-3.3.1.jar!/:3.3.1]
at org.springframework.util.function.ThrowingConsumer$1.acceptWithException(ThrowingConsumer.java:83) ~[spring-core-6.1.10.jar!/:6.1.10]
at org.springframework.util.function.ThrowingConsumer.accept(ThrowingConsumer.java:60) ~[spring-core-6.1.10.jar!/:6.1.10]
at org.springframework.util.function.ThrowingConsumer$1.accept(ThrowingConsumer.java:88) ~[spring-core-6.1.10.jar!/:6.1.10]
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:798) ~[spring-boot-3.3.1.jar!/:3.3.1]
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:789) ~[spring-boot-3.3.1.jar!/:3.3.1]
at org.springframework.boot.SpringApplication.lambda$callRunners$3(SpringApplication.java:774) ~[spring-boot-3.3.1.jar!/:3.3.1]
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) ~[na:na]
at java.base/java.util.stream.SortedOps$SizedRefSortingSink.end(SortedOps.java:357) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:510) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) ~[na:na]
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) ~[na:na]
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:na]
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) ~[na:na]
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:774) ~[spring-boot-3.3.1.jar!/:3.3.1]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:342) ~[spring-boot-3.3.1.jar!/:3.3.1]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1363) ~[spring-boot-3.3.1.jar!/:3.3.1]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1352) ~[spring-boot-3.3.1.jar!/:3.3.1]
at org.sampler.algorithm.Application.main(Application.java:43) ~[!/:0.0.1-SNAPSHOT]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[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:568) ~[na:na]
at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:91) ~[algorithm-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT]
at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:53) ~[algorithm-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT]
at org.springframework.boot.loader.launch.JarLauncher.main(JarLauncher.java:58) ~[algorithm-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT]

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

No branches or pull requests

4 participants