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

IllegalStateException: Error trying to create the prototypeEntityBean for class #2689

Closed
PromanSEW opened this issue May 12, 2022 · 16 comments
Closed

Comments

@PromanSEW
Copy link
Contributor

PromanSEW commented May 12, 2022

See original discussion here:
playframework/play-ebean#278 (comment)

Expected behavior

Start successfully after upgrade to Ebean 13.6.0 from 12.16.1

Actual behavior

Crash

Steps to reproduce

Simple model with costructor

@Entity
@Table(name = "fishes")
public class Fish extends Model {
	@Id
	public int id;
	@Column(nullable = false)
	public String name;

	public Fish(String name) {
		this.name = name;
	}

	private void setName(String name) {
		this.name = name;
	}
}

Crash:
https://gist.github.com/PromanSEW/c101189d0f58eba5bdfccf828643fac2
Play Ebean source:
https://github.com/playframework/play-ebean/blob/main/play-ebean/src/main/java/play/db/ebean/EbeanDynamicEvolutions.java

@PromanSEW
Copy link
Contributor Author

PromanSEW commented May 12, 2022

I can provide full reproducer project, if needed

@rbygrave
Copy link
Member

rbygrave commented May 12, 2022

You will need to provide a way to reproduce @PromanSEW .

  • The model Fish provided above has no package, has a private setName() method etc that doesn't make any sense.

Another way to test the enhancement of a model like Fish would be to use https://github.com/ebean-orm-examples/example-minimal ... add it to that and reproduce.

As a side note, just to say that I think play-ebean should ditch it's "evolutions" and just use Ebean database migrations.

PromanSEW added a commit to PromanSEW/ebean_example that referenced this issue May 12, 2022
@PromanSEW
Copy link
Contributor Author

Here is my reproducer
https://github.com/PromanSEW/ebean_example
If you set ebeanVersion to 12.16.1, all works fine
On 13.6.0 app crashed, it is definitely regression

@xabolcs
Copy link

xabolcs commented May 12, 2022

Here is my reproducer https://github.com/PromanSEW/ebean_example

"This is not the web page you are looking for."

@PromanSEW
Copy link
Contributor Author

Sorry, fixed repository visibility

@rbygrave
Copy link
Member

rbygrave commented May 13, 2022

Ok so given:

public class FishTest {

    @Test
    public void testMe() {
        Class<Fish> fishClass = Fish.class;

        Method[] methods = fishClass.getMethods();
        Class<?>[] interfaces = fishClass.getInterfaces();
        try {
            EntityBean entityBean = (EntityBean) fishClass.getDeclaredConstructor().newInstance();

        } catch (Exception e) {
            throw new IllegalStateException("Error trying to create the prototypeEntityBean for " + fishClass, e);
        }
    }
}

We see:

java.lang.IllegalStateException: Error trying to create the prototypeEntityBean for class models.Fish

	at models.FishTest.testMe(FishTest.java:21)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
	at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
	at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
	at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: java.lang.reflect.InvocationTargetException
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
	at models.FishTest.testMe(FishTest.java:18)
	... 27 more
Caused by: java.lang.InstantiationError: io.ebean.bean.EntityBeanIntercept
	at models.Fish.<init>(Fish.java:1)
	... 32 more

The root cause being: java.lang.InstantiationError: io.ebean.bean.EntityBeanIntercept

Now, why this occurs is because ebean-agent "detects" the version of ebean it is enhancing for. It does this by loading a resource
which is at: https://github.com/ebean-orm/ebean/blob/master/ebean-core/src/main/resources/META-INF/ebean-version.mf#L1

This version 141 tells the ebean-agent to enhance for that version. Now, in 13.6.0 Ebean included a change such that EntityBeanIntercept went to being an interface - #2626

The enhancement being used in play-ebean, isn't using this "version detection" mechanism so it's enhancing as though EntityBeanInterface is still a concrete class. Hence, newing up a EntityBeanInterface fails (as it's an interface in 13.6.0)

To explicitly tell ebean-agent to use version 141

  • Add a ebean.mf manifest file in the classpath that the enhancement agent runs in when it does the enhancement like:

ebean.mf

ebean-version: 141

@PromanSEW
Copy link
Contributor Author

Thanks, I created ebean-version.mf with ebean-version: 141 and it fixes app
I will think how to adapt play-ebean to this change

@rbygrave
Copy link
Member

Yeah cool. Let me know if you have questions / thoughts that I can help with or feedback on.

@PromanSEW
Copy link
Contributor Author

PromanSEW commented May 13, 2022

I am idiot... I checked on 12.16.1... Оn 13.6.0 still crashed :(
But evolution script was updated... Interesting...

@PromanSEW
Copy link
Contributor Author

PromanSEW commented May 13, 2022

The problem is that sbt-play-ebean uses ebean-agent 12.16.1 in it's (sbt) classpath while enhancing, I think
When app classpath uses Ebean 13.6.0
So adding ebean.mf to play-ebean or app resources has no effect...

@PromanSEW
Copy link
Contributor Author

Closed in favor of playframework/play-ebean#290

@zacker330
Copy link

I am stucking in this issue with:

  • springboot3.1.0
  • Ebean 13.25.2-jakarta
  • Ebeant agent 13.26.0

After the source packaged by by Bazel and rules_spring. I ran command:

java -javaagent:bazel-bin/external/maven/v1/https/maven.aliyun.com/repository/public/io/ebean/ebean-agent/13.26.0/ebean-agent-13.26.0.jar -jar bazel-bin/server/src/main/java/codes/showme/ossl/server/springboot.jar  

Then it failed to start with the same issue this issue described.

It's there any suggestion to fix this issue? Thanks.

@rbygrave
Copy link
Member

same issue this issue described

The exactly same stack trace? The exact same root cause? Check all the ebean-version.mf manifest files in the class path looking for the version number in there.

Did you try added a ebean.mf file into the class path as was suggested above in: "Add a ebean.mf manifest file in the classpath that the enhancement agent runs in when it does the enhancement like:" ?

@zacker330
Copy link

same issue this issue described

The exactly same stack trace? The exact same root cause? Check all the ebean-version.mf manifest files in the class path looking for the version number in there.

Did you try added a ebean.mf file into the class path as was suggested above in: "Add a ebean.mf manifest file in the classpath that the enhancement agent runs in when it does the enhancement like:" ?

Thanks for @rbygrave 's kind. I unpackaged the ebean-api's jar to check that file, the content is: ebean-version: 143. I even had put an ebean-version.mf file into META-INF folder. Here's the folder structure of springboot jar file Bazel packaged:
Screen Shot 2024-01-18 at 8 18 39 PM

Here's the stack traces:

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [io.ebean.Database]: Factory method 'accountDatabase' threw exception with message: Error trying to create the prototypeEntityBean for class codes.showme.ossl.artifact.Artifact
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:171) ~[processed_spring-beans-6.0.9.jar!/:6.0.9]
        at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:655) ~[processed_spring-beans-6.0.9.jar!/:6.0.9]
        ... 25 common frames omitted
Caused by: java.lang.IllegalStateException: Error trying to create the prototypeEntityBean for class codes.showme.ossl.artifact.Artifact
        at io.ebeaninternal.server.deploy.BeanDescriptor.createPrototypeEntityBean(BeanDescriptor.java:419) ~[processed_ebean-core-13.25.2-jakarta.jar!/:13.25.2-jakarta]
        at io.ebeaninternal.server.deploy.BeanDescriptor.<init>(BeanDescriptor.java:246) ~[processed_ebean-core-13.25.2-jakarta.jar!/:13.25.2-jakarta]
        at io.ebeaninternal.server.deploy.BeanDescriptorManager.registerDescriptor(BeanDescriptorManager.java:621) ~[processed_ebean-core-13.25.2-jakarta.jar!/:13.25.2-jakarta]
        at io.ebeaninternal.server.deploy.BeanDescriptorManager.readEntityRelationships(BeanDescriptorManager.java:736) ~[processed_ebean-core-13.25.2-jakarta.jar!/:13.25.2-jakarta]
        at io.ebeaninternal.server.deploy.BeanDescriptorManager.deploy(BeanDescriptorManager.java:297) ~[processed_ebean-core-13.25.2-jakarta.jar!/:13.25.2-jakarta]
        at io.ebeaninternal.server.core.InternalConfiguration.<init>(InternalConfiguration.java:127) ~[processed_ebean-core-13.25.2-jakarta.jar!/:13.25.2-jakarta]
        at io.ebeaninternal.server.core.DefaultContainer.createServer(DefaultContainer.java:118) ~[processed_ebean-core-13.25.2-jakarta.jar!/:13.25.2-jakarta]
        at io.ebeaninternal.server.core.DefaultContainer.createServer(DefaultContainer.java:33) ~[processed_ebean-core-13.25.2-jakarta.jar!/:13.25.2-jakarta]
        at io.ebean.DatabaseFactory.createInternal(DatabaseFactory.java:135) ~[processed_ebean-api-13.25.2-jakarta.jar!/:13.25.2-jakarta]
        at io.ebean.DatabaseFactory.create(DatabaseFactory.java:84) ~[processed_ebean-api-13.25.2-jakarta.jar!/:13.25.2-jakarta]
        at codes.showme.ossl.server.config.EbeanDatabaseConfig.accountDatabase(EbeanDatabaseConfig.java:101) ~[classes!/:na]
        at codes.showme.ossl.server.config.EbeanDatabaseConfig$$SpringCGLIB$$0.CGLIB$accountDatabase$1(<generated>) ~[classes!/:na]
        at codes.showme.ossl.server.config.EbeanDatabaseConfig$$SpringCGLIB$$2.invoke(<generated>) ~[classes!/:na]
        at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) ~[processed_spring-core-6.0.9.jar!/:6.0.9]
        at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) ~[processed_spring-context-6.0.9.jar!/:6.0.9]
        at codes.showme.ossl.server.config.EbeanDatabaseConfig$$SpringCGLIB$$0.accountDatabase(<generated>) ~[classes!/:na]
        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.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:139) ~[processed_spring-beans-6.0.9.jar!/:6.0.9]
        ... 26 common frames omitted
Caused by: java.lang.reflect.InvocationTargetException: null
        at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:na]
        at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77) ~[na:na]
        at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:na]
        at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499) ~[na:na]
        at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480) ~[na:na]
        at io.ebeaninternal.server.deploy.BeanDescriptor.createPrototypeEntityBean(BeanDescriptor.java:417) ~[processed_ebean-core-13.25.2-jakarta.jar!/:13.25.2-jakarta]
        ... 46 common frames omitted
Caused by: java.lang.InstantiationError: io.ebean.bean.EntityBeanIntercept
        at codes.showme.ossl.artifact.Artifact.<init>(Artifact.java:148) ~[libartifact.jar!/:na]
        ... 52 common frames omitted


Finally, I switch back to 13.5.0. The issue disappeared.

@rbygrave
Copy link
Member

I believe if we explicitly append =version=143 to the ebean-agent.jar command line like below:

java -javaagent:bazel-bin/ ... /ebean-agent-13.26.0.jar=version=143 -jar bazel-bin/  ...  /springboot.jar  

... then this will work with ebean version 13.26.0. This is suggesting the issue is that the ebean-agent is unable to load the ebean-version.mf resources when the application is packaged like this as a spring uber jar. That means that the ebean-agent is unable to determine the version of ebean that is being used ... and therefore the ebean-agent assumes an older version of ebean is being used [for backwards compatible reasons].

The =version=143 added to the command line argument means that the ebean-agent will parse that and then explicitly use the "ebean version" (which is currently 143).

An alternative that might be interesting to try would be to hack the springboot.jar to add a ebean.mf resource right at the top level in the jar [because the ebean agent is running with a class loader that does not understand the uberjar layout].

@zacker330
Copy link

I believe if we explicitly append =version=143 to the ebean-agent.jar command line like below:

java -javaagent:bazel-bin/ ... /ebean-agent-13.26.0.jar=version=143 -jar bazel-bin/  ...  /springboot.jar  

... then this will work with ebean version 13.26.0. This is suggesting the issue is that the ebean-agent is unable to load the ebean-version.mf resources when the application is packaged like this as a spring uber jar. That means that the ebean-agent is unable to determine the version of ebean that is being used ... and therefore the ebean-agent assumes an older version of ebean is being used [for backwards compatible reasons].

The =version=143 added to the command line argument means that the ebean-agent will parse that and then explicitly use the "ebean version" (which is currently 143).

An alternative that might be interesting to try would be to hack the springboot.jar to add a ebean.mf resource right at the top level in the jar [because the ebean agent is running with a class loader that does not understand the uberjar layout].

The =version=143 is working. Thanks for your answer.

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

4 participants