jcodemodel icon indicating copy to clipboard operation
jcodemodel copied to clipboard

weird issue with snakeyaml

Open glelouet opened this issue 2 years ago • 11 comments

The following test class

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.nio.charset.Charset;

import org.testng.annotations.Test;
import org.yaml.snakeyaml.LoaderOptions;

import com.helger.jcodemodel.JCodeModel;
import com.helger.jcodemodel.JCodeModelException;
import com.helger.jcodemodel.JDefinedClass;
import com.helger.jcodemodel.JMod;
import com.helger.jcodemodel.writer.JCMWriter;
import com.helger.jcodemodel.writer.OutputStreamCodeWriter;

import fr.lelouet.tools.compilation.inmemory.DynamicClassLoader;

public class SnakeYamlImportErrorTest {

	@Test
	public void testCompiling()
			throws JCodeModelException, ClassNotFoundException, InstantiationException, IllegalAccessException,
			IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, IOException {
		JCodeModel jcm = new JCodeModel();
		JDefinedClass cl = jcm._class("Test");
		cl.field(JMod.PUBLIC, LoaderOptions.class, "options");

		try {
			DynamicClassLoader dcl = new DynamicClassLoader(SnakeYamlImportErrorTest.class.getClassLoader()).withCode(jcm);
			Class<?> compiled = dcl.loadClass("Test");
			compiled.getConstructor().newInstance();
		} catch (Exception e) {
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			OutputStreamCodeWriter acw = new OutputStreamCodeWriter(baos, Charset.defaultCharset());
			new JCMWriter(jcm).build(acw);
			throw new UnsupportedOperationException(baos.toString(), e);
		}
	}

}

fails on snakeyaml dependency 2.0 or 2.3 .

compile diagnostic //Test.java:1: error: package org.yaml.snakeyaml does not exist import org.yaml.snakeyaml.LoaderOptions; ^ compile diagnostic //Test.java:4: error: cannot find symbol public LoaderOptions options; ^ symbol: class LoaderOptions location: class Test FAILED: testCompiling java.lang.UnsupportedOperationException: import org.yaml.snakeyaml.LoaderOptions;

public class Test { public LoaderOptions options; }

at SnakeYamlImportErrorTest.testCompiling(SnakeYamlImportErrorTest.java:36) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:134) at org.testng.internal.TestInvoker.invokeMethod(TestInvoker.java:597) at org.testng.internal.TestInvoker.invokeTestMethod(TestInvoker.java:173) at org.testng.internal.MethodRunner.runInSequence(MethodRunner.java:46) at org.testng.internal.TestInvoker$MethodInvocationAgent.invoke(TestInvoker.java:816) at org.testng.internal.TestInvoker.invokeTestMethods(TestInvoker.java:146) at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:146) at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:128) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at org.testng.TestRunner.privateRun(TestRunner.java:766) at org.testng.TestRunner.run(TestRunner.java:587) at org.testng.SuiteRunner.runTest(SuiteRunner.java:384) at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:378) at org.testng.SuiteRunner.privateRun(SuiteRunner.java:337) at org.testng.SuiteRunner.run(SuiteRunner.java:286) at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:53) at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:96) at org.testng.TestNG.runSuitesSequentially(TestNG.java:1187) at org.testng.TestNG.runSuitesLocally(TestNG.java:1109) at org.testng.TestNG.runSuites(TestNG.java:1039) at org.testng.TestNG.run(TestNG.java:1007) at org.testng.remote.AbstractRemoteTestNG.run(AbstractRemoteTestNG.java:115) at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:251) at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:77) Caused by: java.lang.ClassNotFoundException: Test at java.base/java.lang.ClassLoader.findClass(ClassLoader.java:718) at fr.lelouet.tools.compilation.inmemory.DynamicClassLoader.findClass(DynamicClassLoader.java:53) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:587) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520) at SnakeYamlImportErrorTest.testCompiling(SnakeYamlImportErrorTest.java:30) ... 28 more

It however passes on snakeyaml 1.33 , which has critical security issues

I checked and snakeyaml is not imported with the dependencies (besides testng). If I do a main the same problem arises. It may be a problem with my dynamic classloader, or the way the class is available in the jar (require module ?)

glelouet avatar Sep 27 '23 14:09 glelouet

I tried using other libs, or using different class in snakeyam.

result is, issue only appears snakeyaml v2.0+ and with other classes in that lib too.

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.nio.charset.Charset;

import org.testng.Assert;
import org.testng.annotations.Test;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.helger.jcodemodel.JCodeModel;
import com.helger.jcodemodel.JCodeModelException;
import com.helger.jcodemodel.JDefinedClass;
import com.helger.jcodemodel.JMod;
import com.helger.jcodemodel.writer.JCMWriter;
import com.helger.jcodemodel.writer.OutputStreamCodeWriter;

import fr.lelouet.tools.compilation.inmemory.DynamicClassLoader;

public class SnakeYamlImportErrorTest {

	public void compileAndTest(Class<?> fieldClass) throws JCodeModelException, IOException {
		JCodeModel jcm = new JCodeModel();
		JDefinedClass cl = jcm._class("Test");
		cl.field(JMod.PUBLIC, fieldClass, "field");

		try {
			DynamicClassLoader dcl = new DynamicClassLoader(SnakeYamlImportErrorTest.class.getClassLoader()).withCode(jcm);
			Class<?> compiled = dcl.loadClass(cl.name());
			compiled.getConstructor().newInstance();
		} catch (Exception e) {
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			OutputStreamCodeWriter acw = new OutputStreamCodeWriter(baos, Charset.defaultCharset());
			new JCMWriter(jcm).build(acw);
			throw new UnsupportedOperationException(baos.toString(), e);
		}
	}

	@Test
	public void testCompilingLoader() throws JCodeModelException, IOException {
		compileAndTest(LoaderOptions.class);
	}

	@Test
	public void testCompilingYaml() throws JCodeModelException, IOException {
		compileAndTest(Yaml.class);
	}

	@Test
	public void testCompilingString() throws JCodeModelException, IOException {
		compileAndTest(String.class);
	}

	@Test
	public void testCompilingJCM() throws JCodeModelException, IOException {
		compileAndTest(JCodeModel.class);
	}

	@Test
	public void testCompilingJackson() throws JCodeModelException, IOException {
		compileAndTest(ObjectMapper.class);
	}

	@Test
	public void directAccess()
			throws JCodeModelException, ClassNotFoundException, InstantiationException, IllegalAccessException,
			IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, IOException {
		JCodeModel jcm = new JCodeModel();
		jcm._class("Test");

		DynamicClassLoader dcl = new DynamicClassLoader(SnakeYamlImportErrorTest.class.getClassLoader()).withCode(jcm);
		Class<?> lcl = dcl.loadClass(Yaml.class.getName());
		Assert.assertNotNull(lcl);
		Class<?> lcl2 = dcl.loadClass(LoaderOptions.class.getName());
		Assert.assertNotNull(lcl2);
	}

}

When I switch to snakeyaml v1.33 all tests pass ; when I switch to 2.0

[ERROR] Failures: [ERROR] SnakeYamlImportErrorTest.testCompilingLoader:42->compileAndTest:36 UnsupportedOperation import org.yaml.snakeyaml.LoaderOptions;

public class Test { public LoaderOptions field; }

[ERROR] SnakeYamlImportErrorTest.testCompilingYaml:47->compileAndTest:36 UnsupportedOperation import org.yaml.snakeyaml.Yaml;

public class Test { public Yaml field; }

glelouet avatar Sep 27 '23 15:09 glelouet

Is it with head revision or the 3.x version?

phax avatar Sep 27 '23 15:09 phax

jcodemodel version is 3.4.1

I keep that class in my compiler to be sure the snakeyaml version allows to compile( when there is a huge number of classes to compile, I don't want it to fail at compile time)

glelouet avatar Sep 27 '23 15:09 glelouet

Note that it could as well be an issue with my own dynamicClassLoader code. I tried to find it in your source but could not :'( :'( :'( though I remembered having submitted a patch in that regard.

glelouet avatar Sep 27 '23 15:09 glelouet

Yes I know - I didn't do much in this project lately - and the proposed changes were so huge I couldn't understand them properly without investing more time. Maybe Snakeyaml 2.x needs a later JVM version?

phax avatar Sep 27 '23 15:09 phax

I checked and there was no update here

https://mvnrepository.com/artifact/com.helger/jcodemodel

(I just spent a lot of time merging all my dependencies management in the same pom)

glelouet avatar Sep 27 '23 15:09 glelouet

sakeyaml uses java17 (which was specified in my projet java.version=17 ). I tried bumping java.version=18, no positive effect.

glelouet avatar Sep 27 '23 15:09 glelouet

Snakeyaml 2.2 uses 1.7 according to https://search.maven.org/artifact/org.yaml/snakeyaml/2.2/bundle As long as it is 1.7 and not 17 we should be okay

phax avatar Sep 27 '23 15:09 phax

Sorry can't help you out in any more detail - I an in front of a 4 week leave and need to finish tons of other things first :( Back in November. Good luck

phax avatar Sep 27 '23 15:09 phax

No problem :) I've had this for a year now, so it's not important. Just wanted to be sure where it came from, so I isolated it.

java17 is the version specified in the root pom. Now java 21 :

	<properties>
		<java.version>21</java.version>
		<maven.compiler.source>${java.version}</maven.compiler.source>
		<maven.compiler.target>${java.version}</maven.compiler.target>
	</properties>
	<build>
		<pluginManagement>
			<plugins>
				<!-- update https://mvnrepository.com/artifact/org.apache.maven.plugins -->
				<plugin>
					<groupId>org.apache.maven.plugins</groupId>
					<artifactId>maven-compiler-plugin</artifactId>
					<version>3.11.0</version>
					<configuration>
						<release>${java.version}</release>
					</configuration>
				</plugin>

This is the newish (3years now?) way to specify java version as shown by maven :

[INFO] --- maven-compiler-plugin:3.11.0:testCompile (default-testCompile) @ compiler --- [INFO] Changes detected - recompiling the module! :dependency [INFO] Compiling 3 source files with javac [debug release 21] to target/test-classes

Still same errors :

[ERROR] Failures: [ERROR] SnakeYamlImportErrorTest.testCompilingLoader:42->compileAndTest:36 UnsupportedOperation import org.yaml.snakeyaml.LoaderOptions;

public class Test { public LoaderOptions field; }

[ERROR] SnakeYamlImportErrorTest.testCompilingYaml:47->compileAndTest:36 UnsupportedOperation import org.yaml.snakeyaml.Yaml;

public class Test { public Yaml field; }

glelouet avatar Sep 27 '23 16:09 glelouet

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Jan 07 '24 11:01 stale[bot]