OpenHFT / Chronicle-Values

http://chronicle.software
Other
104 stars 37 forks source link

LinkageError when java sources are present in the classpath. #7

Closed lsubra closed 3 years ago

lsubra commented 8 years ago

Stack trace

java.lang.AssertionError: java.lang.LinkageError: loader (instance of sun/misc/Launcher$AppClassLoader): attempted duplicate class definition for name: "com/universe/codegen/testfiles/primitives/Primitives" at net.openhft.chronicle.values.CompilerUtils.defineClass(CompilerUtils.java:84) at net.openhft.chronicle.values.CachedCompiler.loadFromJava(CachedCompiler.java:82) at net.openhft.chronicle.values.ValueModel.createClass(ValueModel.java:347) at net.openhft.chronicle.values.ValueModel.createNativeClass(ValueModel.java:322) at net.openhft.chronicle.values.ValueModel.nativeClass(ValueModel.java:298) at net.openhft.chronicle.values.Values.nativeClassFor(Values.java:82) at net.openhft.chronicle.values.Values.newNativeReference(Values.java:50)

Happening in

Chronicle-Values version 1.5.1. Haven't tested with other versions.

To reproduce:

  1. Create a Values interface "com.a.b.MyInterface"
  2. Include "com/a/b/MyInterface.java" in the resource path (exactly at that location)
  3. Invoke Values.newNativeReference(MyInterface.class) and it fails with LinkageError.

    Workarounds:

    • Move MyInterface.java to a different resource path (i.e. anything but com/a/b/MyInterface.java). This fixes the issue, but it is ugly.

      Potential Root Cause:

    • When I ran the debugger: https://github.com/OpenHFT/Chronicle-Values/blob/chronicle-values-1.5.1/src/main/java/net/openhft/chronicle/values/CachedCompiler.java#L52 was returning both MyInterface$$NATIVE (the generated class) and MyInterface when MyInterface.java is "alongside" MyInterface.class. Without the .java file, it returns only MyInterface$$NATIVE and doesn't throw LinkageError.

      My usecase:

    • I am writing tests for a codegenerator that produces Values Interface source code (like MyInterface.java) as its output.
    • I want to verify the codegenerator's output against a version-controlled, in-resource-path, MyInterface.java.
    • In the test, MyInterface is also compiled as a regular class so I can also verify that it is compatible with Values (i.e. Values.newNativeReference(..) and getter/setter etc works).
    • For now, I use the ugly workaround and just put MyInterface.java in a different directory (compared to its package).
peter-lawrey commented 8 years ago

It is true that you can't redefine a class you have already loaded. If you provide the class yourself you also have to provide the additional classes which are generated.

Peter. On 19 Jun 2016 12:49 AM, "lsubra" notifications@github.com wrote:

Stack trace

java.lang.AssertionError: java.lang.LinkageError: loader (instance of sun/misc/Launcher$AppClassLoader): attempted duplicate class definition for name: "com/universe/codegen/testfiles/primitives/Primitives" at net.openhft.chronicle.values.CompilerUtils.defineClass(CompilerUtils.java:84) at net.openhft.chronicle.values.CachedCompiler.loadFromJava(CachedCompiler.java:82) at net.openhft.chronicle.values.ValueModel.createClass(ValueModel.java:347) at net.openhft.chronicle.values.ValueModel.createNativeClass(ValueModel.java:322) at net.openhft.chronicle.values.ValueModel.nativeClass(ValueModel.java:298) at net.openhft.chronicle.values.Values.nativeClassFor(Values.java:82) at net.openhft.chronicle.values.Values.newNativeReference(Values.java:50) Happening in

Chronicle-Values version 1.5.1 To reproduce:

  1. Create a Values interface "com.a.b.MyInterface"
  2. Include "com/a/b/MyInterface.java" in the resource path (exactly at that location)
  3. Invoke Values.newNativeReference(MyInterface.class) and it fails with LinkageError.

Workarounds:

  • Move MyInterface.java to a different resource path (i.e. anything but com/a/b/MyInterface.java). This fixes the issue, but it is ugly.

Potential Root Cause:

My usecase:

  • I am writing tests for a codegenerator that produces Values Interface source code (like MyInterface.java) as its output.
  • I want to verify the codegenerator's output against a version-controlled, in-resource-path, MyInterface.java.
  • In the test, MyInterface is also compiled as a regular class so I can also verify that it is compatible with Values (i.e. Values.newNativeReference(..) and getter/setter etc works).
  • For now, I use the ugly workaround and just put MyInterface.java in a different directory (compared to its package).

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/OpenHFT/Chronicle-Values/issues/7, or mute the thread https://github.com/notifications/unsubscribe/ABBU8ZzRrVvNdee1LYRpvmfOtHhDwTXyks5qNMpjgaJpZM4I5F2o .

leventov commented 8 years ago

This is another one issue coming from runtime Java code compilation.. Next version of Chronicle Values should have compile-time code generation. This is not so much work, but I'm afraid no one have incentive to do this in the nearest future.

lsubra commented 8 years ago

@peter-lawrey Just to be clear, I am not providing an implementation class, just placing the source file of the interface in the resource path.

@leventov Compile time generation would be ideal and I was wondering why runtime generation was chosen initially. Please feel free to close this out if it isn't a priority.

peter-lawrey commented 8 years ago

Runtime generation is simpler to build as you don't have to specify which classes to be prebuilt.

Compile time generation is more efficient on loading.

On 19 June 2016 at 13:41, lsubra notifications@github.com wrote:

@peter-lawrey https://github.com/peter-lawrey Just to be clear, I am not providing an implementation class, just placing the source file of the interface in the resource path.

@leventov https://github.com/leventov Compile time generation would be ideal and I was wondering why runtime generation was chosen initially. Please feel free to close this out if it isn't a priority.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/OpenHFT/Chronicle-Values/issues/7#issuecomment-227010118, or mute the thread https://github.com/notifications/unsubscribe/ABBU8X53MTsfQT8LOon_XGFdAJ9etWBoks5qNX8xgaJpZM4I5F2o .

leventov commented 8 years ago

@peter-lawrey in this case I think we should trivially prebuild both native and heap implementations. Since there are only two of them and they contain not so much code, cost of building but not using an implementation (typically the heap implementation) is minimal.

peter-lawrey commented 8 years ago

We would need a means of identifying which interfaces to prebuild.

On 19 June 2016 at 20:58, Roman Leventov notifications@github.com wrote:

@peter-lawrey https://github.com/peter-lawrey in this case I think we should trivially prebuild both native and heap implementations. Since there are only two of them and they contain not so much code, cost of building but not using an implementation (typically the heap implementation) is minimal.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/OpenHFT/Chronicle-Values/issues/7#issuecomment-227031365, or mute the thread https://github.com/notifications/unsubscribe/ABBU8T-CGH9PoAzcg4Nie1uf6pPLY_Xhks5qNeWogaJpZM4I5F2o .

leventov commented 8 years ago

@peter-lawrey via annotation, @Value on interfaces to build.

peter-lawrey commented 8 years ago

Although I dislike annotation processing, I suspect it is the simplest solution in this case.

On 19 June 2016 at 21:12, Roman Leventov notifications@github.com wrote:

@peter-lawrey https://github.com/peter-lawrey via annotation, @Value on interfaces to build.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/OpenHFT/Chronicle-Values/issues/7#issuecomment-227032308, or mute the thread https://github.com/notifications/unsubscribe/ABBU8cIRzqWMQZIMNJ1PXGMYLg_ywsH2ks5qNej5gaJpZM4I5F2o .

leventov commented 8 years ago

@peter-lawrey why do you dislike annotation processing?

peter-lawrey commented 8 years ago

It complicates the build process but adding another step and it's an opportunity for things to go wrong in ways many don't understand. e.g. the generated code should have updated but didn't.

On 20 June 2016 at 02:24, Roman Leventov notifications@github.com wrote:

@peter-lawrey https://github.com/peter-lawrey why do you dislike annotation processing?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/OpenHFT/Chronicle-Values/issues/7#issuecomment-227033147, or mute the thread https://github.com/notifications/unsubscribe/ABBU8XPFsO_DpU9lRdGmWIYPrXIfzZTQks5qNeuygaJpZM4I5F2o .

peter-lawrey commented 8 years ago

Though this is not a reason to not do it, esp if the alternatives are no better.

On 20 June 2016 at 15:57, Peter Lawrey peter.lawrey@chronicle.software wrote:

It complicates the build process but adding another step and it's an opportunity for things to go wrong in ways many don't understand. e.g. the generated code should have updated but didn't.

On 20 June 2016 at 02:24, Roman Leventov notifications@github.com wrote:

@peter-lawrey https://github.com/peter-lawrey why do you dislike annotation processing?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/OpenHFT/Chronicle-Values/issues/7#issuecomment-227033147, or mute the thread https://github.com/notifications/unsubscribe/ABBU8XPFsO_DpU9lRdGmWIYPrXIfzZTQks5qNeuygaJpZM4I5F2o .

RobAustin commented 3 years ago

closing as this issue is very old, please let me know if you wish us to reopen