-
Notifications
You must be signed in to change notification settings - Fork 13
Support initialisation of ToMany collections using List.of() etc #220
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
Changes from all commits
edd262a
3377e64
20b1bc4
af1a203
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| package io.ebean.enhance; | ||
|
|
||
| /** | ||
| * Some unexpected bytecode that can't be supported. | ||
| * <p> | ||
| * For example, some unsupported OneToMany collection initialisation. | ||
| */ | ||
| public class EnhancementException extends RuntimeException { | ||
| public EnhancementException(String message) { | ||
| super(message); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| package test.enhancement; | ||
|
|
||
| import io.ebean.common.BeanList; | ||
| import io.ebean.common.BeanMap; | ||
| import io.ebean.common.BeanSet; | ||
| import org.junit.jupiter.api.Test; | ||
| import test.model.Contact; | ||
| import test.model.WithInitialisedCollections2; | ||
|
|
||
| import static org.assertj.core.api.Assertions.assertThat; | ||
|
|
||
| class WithInitialisedCollections2Test extends BaseTest { | ||
|
|
||
| @Test | ||
| void oneToMany_initialisationCode_expect_removed() { | ||
| WithInitialisedCollections2 bean = new WithInitialisedCollections2(); | ||
|
|
||
| assertThat(bean.listOf()).isInstanceOf(BeanList.class); | ||
| assertThat(bean.listCollEmpty()).isInstanceOf(BeanList.class); | ||
| assertThat(bean.setOf()).isInstanceOf(BeanSet.class); | ||
| assertThat(bean.setCollEmpty()).isInstanceOf(BeanSet.class); | ||
| assertThat(bean.mapOf()).isInstanceOf(BeanMap.class); | ||
| assertThat(bean.mapCollEmpty()).isInstanceOf(BeanMap.class); | ||
|
|
||
|
|
||
| assertThat(bean.transientList()).isNotInstanceOf(BeanList.class); | ||
| assertThat(bean.transientList2()).isNotInstanceOf(BeanList.class); | ||
| assertThat(bean.transientSet()).isNotInstanceOf(BeanSet.class); | ||
| assertThat(bean.transientSet2()).isNotInstanceOf(BeanSet.class); | ||
| assertThat(bean.transientMap()).isNotInstanceOf(BeanMap.class); | ||
| assertThat(bean.transientMap2()).isNotInstanceOf(BeanMap.class); | ||
|
|
||
|
|
||
| // these methods work because the underlying collection is a BeanCollection | ||
| bean.listOf().add(new Contact("junk")); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My expectation is, that this should fail. BTW. There are other ways to initialize immutable lists:
I think, the agent should fail or at least warn, if an unknown initialization is detectef
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
That is reasonable. My expectation was that people wouldn't use
The initialisation for OneToMany and ManyToMany is removed. So for example, if we detect So this PR was done such that initialisation via That is, the only reasons why we'd choose to initialise OneToMany collections in such a way is so that (A) the fields can be final and (B) it gives the impression to people reading the code that the collection will not be null. So that all said, I've pushed another PR just now that detects when initialisation code for OneToMany or ManyToMany isn't supported and throws a new EnhancementException [and for maven we will fail the build at enhancement due when this is detected].
Yes. I think I've just managed to do that with the latest commit pushed here plus a change to the maven plugin to detect and fail the build for that case. The outstanding question I think is, should we support
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I would never have thought of that ;) We would need the following use cases:
if we decide to do, I would expect, that the BeanList/BeanSet etc. is also readonly. So BeanList needs a readOnly flag and the agent must call the new constructor I can imagine use cases, where I want to protect the modification of that list by someone else. but this is more theoretical, so it would be also OK to throw an error in the enhancer
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I have no intention of ebean supporting unsorted sets/maps. I don't think that is a need / requirement.
I don't think we can easily do that at this point. I don't want to try to get that clever unless we have to. My suspicion is that I don't think people are thinking deeply about this. I suspect the use of List.of() was more just a bit of an accident.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reviewing the JPA spec, the initialisation of OneToMany and ManyToMany is vague: "Collection-valued persistent fields and properties must be defined in terms of one of the following collection-valued interfaces regardless of whether the entity class otherwise adheres to the JavaBeans method conventions noted above and whether field or property access is used: java.util.Collection, java.util.Set, java.util.List [3], java.util.Map. The collection implementation type may be used by the application to initialize fields or properties before the entity is made persistent." Noting that stack overflow has - https://stackoverflow.com/questions/20715143/to-initialize-or-not-initialize-jpa-relationship-mappings At this stage, it feels like the safest option would be to not support List.of() and Collections.emptyList() etc as long as we can explicitly fail the enhancement. Noting that there might have "holes" in this detection like an application that ONLY using javaagent style enhancement could miss an error going to system out [but the entity would not be enhanced so it would not be useable as an entity - it's just the error might get misleading]. |
||
| bean.setOf().add(new Contact("junk")); | ||
| bean.listCollEmpty().add(new Contact("junk")); | ||
| bean.setCollEmpty().add(new Contact("junk")); | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.