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

@NotNull + @Enumerated causes instrumentation failure #3031

Open
rvowles opened this issue Apr 18, 2023 · 13 comments
Open

@NotNull + @Enumerated causes instrumentation failure #3031

rvowles opened this issue Apr 18, 2023 · 13 comments

Comments

@rvowles
Copy link
Contributor

rvowles commented Apr 18, 2023

Expected behavior

I have a bean with this, it happened as I upgraded from 13.10 -> 13.17

@Enumerated(value=EnumType.STRING)
@NotNull
private SubscriptionStatus subscriptionStatus = SubscriptionStatus.FREE_TRIAL;

If I annotate this way, it crashes with

java.lang.RuntimeException: Error reading annotations for dev.featurehub.app.cs.db.models.CsOrganisation
at io.ebeaninternal.server.deploy.parse.ReadAnnotations.readInitial(ReadAnnotations.java:31) ~[ebean-core-13.17.0-jakarta.jar:13.17.0-jakarta]
at io.ebeaninternal.server.deploy.BeanDescriptorManager.createDeployBeanInfo(BeanDescriptorManager.java:1168) ~[ebean-core-13.17.0-jakarta.jar:13.17.0-jakarta]
at io.ebeaninternal.server.deploy.BeanDescriptorManager.readEntityDeploymentInitial(BeanDescriptorManager.java:641) ~[ebean-core-13.17.0-jakarta.jar:13.17.0-jakarta]
at io.ebeaninternal.server.deploy.BeanDescriptorManager.deploy(BeanDescriptorManager.java:290) ~[ebean-core-13.17.0-jakarta.jar:13.17.0-jakarta]
at io.ebeaninternal.server.core.InternalConfiguration.(InternalConfiguration.java:129) ~[ebean-core-13.17.0-jakarta.jar:13.17.0-jakarta]
at io.ebeaninternal.server.core.DefaultContainer.createServer(DefaultContainer.java:104) ~[ebean-core-13.17.0-jakarta.jar:13.17.0-jakarta]
at io.ebeaninternal.server.core.DefaultContainer.createServer(DefaultContainer.java:57) ~[ebean-core-13.17.0-jakarta.jar:13.17.0-jakarta]
at io.ebeaninternal.server.core.DefaultContainer.createServer(DefaultContainer.java:29) ~[ebean-core-13.17.0-jakarta.jar:13.17.0-jakarta]
at io.ebean.DatabaseFactory.create(DatabaseFactory.java:60) ~[ebean-api-13.17.0-jakarta.jar:13.17.0-jakarta]
at io.ebean.DbContext.getWithCreate(DbContext.java:98) ~[ebean-api-13.17.0-jakarta.jar:13.17.0-jakarta]
a
Caused by: jakarta.persistence.PersistenceException: Error mapping property dev.featurehub.app.cs.db.models.CsOrganisation.subscriptionStatus - Error mapping Enum type:class dev.featurehub.app.common.model.SubscriptionStatus It is mapped using 2 different modes when only one is supported (ORDINAL, STRING or an Ebean mapping)

It seems to try and process the annotation twice.

If I drop the @NotNull and replace it with a @Column(nullable = false) then its ok.

@rbygrave
Copy link
Member

Error mapping Enum type:class dev.featurehub.app.common.model.SubscriptionStatus It is mapped using 2 different modes when only one is supported (ORDINAL, STRING or an Ebean mapping)

What does SubscriptionStatus look like? Does it have any mappings?

@rvowles
Copy link
Contributor Author

rvowles commented Apr 18, 2023

it did look like this:

/*

package dev.featurehub.app.common.model;

import com.fasterxml.jackson.annotation.;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import jakarta.validation.constraints.
;
import java.util.HashMap;
import java.util.Map;

/** Gets or Sets SubscriptionStatus */
public enum SubscriptionStatus {
ACTIVE("ACTIVE"),

CANCELLED("CANCELLED"),

UNPAID("UNPAID"),

PAST_DUE("PAST_DUE"),

FREE_TRIAL("FREE_TRIAL"),

TRIAL_EXPIRED("TRIAL_EXPIRED");

private String value;

SubscriptionStatus(String value) {
this.value = value;
}

@JsonValue
public String getValue() {
return value;
}

@OverRide
public String toString() {
return String.valueOf(value);
}

public SubscriptionStatus copy() {
return this;
}

// can't use map.of
private static Map<String, SubscriptionStatus> fromValues = new HashMap<>();

static {
fromValues.put("ACTIVE", ACTIVE);
fromValues.put("ACTIVE", ACTIVE);
fromValues.put("CANCELLED", CANCELLED);
fromValues.put("CANCELLED", CANCELLED);
fromValues.put("UNPAID", UNPAID);
fromValues.put("UNPAID", UNPAID);
fromValues.put("PAST_DUE", PAST_DUE);
fromValues.put("PAST_DUE", PAST_DUE);
fromValues.put("FREE_TRIAL", FREE_TRIAL);
fromValues.put("FREE_TRIAL", FREE_TRIAL);
fromValues.put("TRIAL_EXPIRED", TRIAL_EXPIRED);
fromValues.put("TRIAL_EXPIRED", TRIAL_EXPIRED);
}

@JsonCreator
public static SubscriptionStatus fromValue(String text) {
return fromValues.get(text);
}
}

but then i found that the @Enumerated was being ignored and it was an INT (full rebuild, depoyed in docker container) - so had to put the @io.ebean.annotation.DbEnumValue back in on the class (the API generator will add ebean annotations on command!) But the `@Column while working for tests it appears, didn't work when running it up, so i have had to remove the NotNull and Column annotations.

@rvowles
Copy link
Contributor Author

rvowles commented Apr 18, 2023

When i debugged into it, it hit that method in DeployUtil twice for the same field - setEnumScalarType - it seemed like it was unhappy about doing that. If I can debug any further to illuminate this I'm happy to!

@rvowles
Copy link
Contributor Author

rvowles commented Apr 19, 2023

This is so weird. When the container starts in k8s, it hits this error when running and crashes. But k8s restarts the container, and it runs ok.

{"@timestamp":"2023-04-19T07:30:12.380+0000","message":"Error in deployment","priority":"ERROR","path":"io.ebean.internal","thread":"main","stack_trace":"java.lang.RuntimeException: Error reading annotations for dev.featurehub.app.cs.db.models.CsOrganisation\n\tio.ebeaninternal.server.deploy.parse.ReadAnnotations.readInitial(ReadAnnotations.java:31) ~[ebean-core-13.17.0-jakarta.jar:13.17.0-jakarta]\n\tio.ebeaninternal.server.deploy.BeanDescriptorManager.createDeployBeanInfo(BeanDescriptorManager.java:1168) ~[ebean-core-13.17.0-jakarta.jar:13.17.0-jakarta]\n\tio.ebeaninternal.server.deploy.BeanDescriptorManager.readEntityDeploymentInitial(BeanDescriptorManager.java:641) ~[ebean-core-13.17.0-jakarta.jar:13.17.0-jakarta]\n\tio.ebeaninternal.server.deploy.BeanDescriptorManager.deploy(BeanDescriptorManager.java:290) ~[ebean-core-13.17.0-jakarta.jar:13.17.0-jakarta]\n\tio.ebeaninternal.server.core.InternalConfiguration.(InternalConfiguration.java:129) ~[ebean-core-13.17.0-jakarta.jar:13.17.0-jakarta]\n\tio.ebeaninternal.server.core.DefaultContainer.createServer(DefaultContainer.java:104) ~[ebean-core-13.17.0-jakarta.jar:13.17.0-jakarta]\n\tio.ebeaninternal.server.core.DefaultContainer.createServer(DefaultContainer.java:29) ~[ebean-core-13.17.0-jakarta.jar:13.17.0-jakarta]\n\tio.ebean.DatabaseFactory.createInternal(DatabaseFactory.java:136) ~[ebean-api-13.17.0-jakarta.jar:13.17.0-jakarta]\n\tio.ebean.DatabaseFactory.create(DatabaseFactory.java:85) ~[ebean-api-13.17.0-jakarta.jar:13.17.0-jakarta]\n\tio.featurehub.app.db.utils.CommonDbFeature.configure(CommonDbFeature.kt:177) ~[common-db-1.1-SNAPSHOT.jar:?]\n\torg.glassfish.jersey.model.internal.CommonConfig.configureFeatures(CommonConfig.java:728) ~[jersey-common-3.1.1.jar:?]\n\t

@rvowles
Copy link
Contributor Author

rvowles commented Apr 19, 2023

Ok - if i swap from JDK 11.11 -> 11.18 it happens, if i swap back it doesn't happen (tumerin).

@rvowles
Copy link
Contributor Author

rvowles commented Apr 19, 2023

I just tried with Amazon's JDK as well and have the same issue.

@rvowles
Copy link
Contributor Author

rvowles commented Apr 19, 2023

and now i try and debug it and i can't trigger it 🤕 fails when running, passes when debugging.

@rbygrave
Copy link
Member

The stack trace at the top is truncated and does not include the caused by: ... which would tell us the underlying cause. Are we able to get that?

@rvowles
Copy link
Contributor Author

rvowles commented Apr 19, 2023

I'm still trying to figure out how to replicate it, it's changing all the time.

@rbygrave
Copy link
Member

The original error is suggesting that SubscriptionStatus is mapped in 2 or more places, where in one place it is a @Enumerated(value=EnumType.STRING) and in the other its a @Enumerated(value=EnumType.ORDINAL) or @Enumerated (or has no @Enumerated or has @DbEnumValue) ?

Is the enum type SubscriptionStatus used in multiple places / mapped in multiple entity beans? Is it mapped consistently in all the places it is used?

@rvowles
Copy link
Contributor Author

rvowles commented Apr 20, 2023

Now that was the trigger I needed to find it thanks @rob-bygrave ! It was an Entity/View that just had it used. It was fine with 13.10/Java 11.11 but with 13.7/11.18 it wasn't. I still cannot reliably reproduce it either, sometimes it happens, sometimes it doesn't. Once it has gone, it has gone for a few hours and then pops up again. I will leave it correctly annotated for now, but I'm wondering if it wouldn't be worthwhile a PR rewording that error message so its more clear what to look for?

@rob-bygrave
Copy link
Contributor

dev.featurehub.app.common.model.SubscriptionStatus It is mapped using 2 different modes when only one is supported (ORDINAL, STRING or an Ebean mapping)

Yeah absolutely. I'll create a PR with some better wording and get you to review the new wording.

cannot reliably reproduce

It's very strange. I can imagine that different JVMs could result in different ordering when it reads the entity classes annotations etc.

I wonder if there is something subtle where it actually does not fail when it really/ideally should fail all the time regardless of the order in which things are read. Hmmm, maybe I should try and reproduce on a minimal model. It sounds like there is a bug where it really should fail with this error and somehow does not.

@rvowles
Copy link
Contributor Author

rvowles commented Apr 21, 2023

Where it was being used was here (like this):

@Entity
@View(name = "cs_organisation", dependentTables = "cs_organisation")
public class CsOrganisationCounters {
  @Aggregation("count(subscription_status)")
  public Long count;

  @NotNull
  public SubscriptionStatus subscriptionStatus;
}

such a heisenbug!

rbygrave added a commit that referenced this issue May 9, 2023
rPraml pushed a commit to FOCONIS/ebean that referenced this issue May 10, 2023
rPraml pushed a commit to FOCONIS/ebean that referenced this issue Aug 3, 2023
rPraml pushed a commit to FOCONIS/ebean that referenced this issue Aug 3, 2023
rPraml pushed a commit to FOCONIS/ebean that referenced this issue Aug 3, 2023
rPraml pushed a commit to FOCONIS/ebean that referenced this issue Aug 3, 2023
rPraml pushed a commit to FOCONIS/ebean that referenced this issue Aug 8, 2023
rPraml pushed a commit to FOCONIS/ebean that referenced this issue Aug 8, 2023
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

3 participants