Bug 544014 - ClassFormatError when composing Functions returning/receiving an array
Summary: ClassFormatError when composing Functions returning/receiving an array
Status: NEW
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 4.10   Edit
Hardware: PC Windows 10
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: JDT-Core-Inbox CLA
QA Contact: Srikanth Sankaran CLA
URL:
Whiteboard: stalebug
Keywords:
Depends on:
Blocks:
 
Reported: 2019-01-31 10:38 EST by Matthias Perktold CLA
Modified: 2023-06-01 04:21 EDT (History)
4 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Matthias Perktold CLA 2019-01-31 10:38:49 EST
Take the following complete example:

  import java.util.function.Function;

  public class ArrFunctionCompositionTest {

    static class A {}
    static class B {}
    static class C {}

    public static void main(String[] args) {
      Function<? super A, ? extends B[]> aToBArr = a -> new B[] { new B() };
      System.out.println(aToBArr.andThen(arr -> new C()).apply(new A()));
    }
  }

It defines a function from A to an array of B, then composes it with another function from an array of bs to C, obtaining a function from A to C. At the end it applies the obtained function to some A and prints the resulting C.

When running this example in Eclipse, I get an error with the following stack trace:
Exception in thread "main" java.lang.ClassFormatError: Method "lambda$1" in class ArrFunctionCompositionTest has illegal signature "(L[LArrFunctionCompositionTest$B;;)LArrFunctionCompositionTest$C;"
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
	at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
	at java.net.URLClassLoader.defineClass(URLClassLoader.java:468)
	at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
	at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
	at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
	at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:495)

Whearas compiling and running the code with javac/java of JDK 8u192 works fine.
Comment 1 Olivier Thomann CLA 2019-01-31 11:29:32 EST
The problem seems to come from the signature computation.
For the capture binding (capture#2-of ? extends ArrFunctionCompositionTest.B[]), we return a signature: L[LArrFunctionCompositionTest$B;; instead of [LArrFunctionCompositionTest$B;

I made that hack:
@Override
public char[] signature() /* Ljava/lang/Object; */ {
	if (this.signature != null)
		return this.signature;

	char[] constantPoolName2 = constantPoolName();
	if (constantPoolName2[0] == '[') {
		return this.signature = constantPoolName2;
	}
	return this.signature = CharOperation.concat('L', constantPoolName2, ';');
}
in org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding and it passed the test. Of course this is a hack.
Comment 2 Stephan Herrmann CLA 2019-01-31 12:50:23 EST
(In reply to Olivier Thomann from comment #1)
> the test. Of course this is a hack.

:)

Does overriding signature() in CaptureBinding fix this? Or perhaps in TypeVariableBinding, which is the guy who delegates constantPoolName() to its bound?
Comment 3 Olivier Thomann CLA 2019-01-31 18:33:53 EST
Yes, I was thinking more something like this in org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding:
	@Override
	public char[] signature() /* Ljava/lang/Object; */ {
		if (this.signature != null)
			return this.signature;

		char[] temp = null;
		if (this.firstBound != null) {
			temp = this.firstBound.constantPoolName();
			if (!this.firstBound.isArrayType()) {
				temp = CharOperation.concat('L', temp, ';');
			}
		} else {
			temp = CharOperation.concat('L', this.superclass.constantPoolName(), ';');
		}
		this.signature = temp;
		return temp;
	}
This passes the given test case.
Comment 4 Eclipse Genie CLA 2021-01-21 11:24:15 EST
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet.

If you have further information on the current state of the bug, please add it. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.

--
The automated Eclipse Genie.
Comment 5 Eclipse Genie CLA 2023-02-23 17:51:37 EST
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet.

If you have further information on the current state of the bug, please add it. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.

--
The automated Eclipse Genie.
Comment 6 Srikanth Sankaran CLA 2023-06-01 04:21:15 EDT
Seems fixed in master