We can write our entities using public fields and not have getters/setters/accessors like:
@Entity
public class Customer {
@Id
public long id;
@Column(length = 100)
public String name;
@OneToMany(mappedBy="customer")
public List<Contact> contacts;
...
}
// just use PUTFIELD and GETFIELD
var customer = new Customer();
customer.name = "Fred";
customer.contacts.add(new Contact(..));
DB.save(customer);
var customer = DB.find(Customer.class, 42);
var id = customer.id;
var name = customer.name;
var city = customer.billingAddress.city;
How to enable entity-field-access
This feature is not enabled by default. We need to explicitly turn it on to use it.
Make sure you are using ebean-agent 13.10.0 or greater
Add a src/main/resources/ebean.mf with a entity-field-access entry like:
entity-field-access: true
If we are NOT using query beans we additionally need to specify the entity-packages that contain entity beans like:
We don't need to do this when using query beans because the querybean-generator automatically adds a META-INF/ebean-generated-info.mf manifest file with the entity-packages entry for us.
What does this feature do?
Background:
Ebean allows our entity beans to have getters/setters/accessors in any form we want - they do NOT have to be strictly getters/setters.
Technically Ebean does not require getters/setters at all but these are the methods that the application code uses/calls in order to read and write field values of the entity bean
Ebean adds it's own accessor methods like _ebean_get_name() and _ebean_set_name(String name) and uses those methods (ok, there is a little more to it but yeah)
Field access enhancement:
What the Ebean enhancement does here is it replaces GETFIELD and PUTFIELD with method calls like _ebean_get_name() and _ebean_set_name(String name).
For example:
customer.name = "Fred";
// Is turned into
customer._ebean_set_name("Fred");
customer.contacts.add(new Contact(..));
// Is turned into
customer._ebean_get_contacts().add(new Contact(..));
var city = customer.billingAddress.city;
// Is turned into
var city = customer._ebean_get_billingAddress()._ebean_get_city();
What this means is that although it looks like we are using "field access / GETFIELD / PUTFIELD" etc the enhancement has changed it to use the methods that Ebean enhancement has added and these methods have all the interception support of dirty checking, lazy loading etc.
We have all the same functionality as if we were using getters/setters/accessors.
Another way to look at it
Ebean enhancement replaces GETFIELD/PUTFIELD calls with its own _ebean_get_name()_ebean_set_name(...) methods. Normally, this is restricted to ONLY doing this replacement on the entity beans themselves.
When using entity-field-access this replacement is extended to any application code.
When should I use this feature?
Currently it's experimental but if you have a lot of entity beans and perhaps a lot of those are from and application perspective "read only" and they are generally "read write" for testing purposes - then you'd be motivated to trying out this feature.
Limitations
Today it works by assuming that classes in the entity-packages are in fact entities. If we have classes that are not entities in the entity packages and we also use field access on those classes that will not work [those GETFIELD/PUTFIELD calls will be changed to method calls like _ebean_get_name() but those methods will not exist as the type isn't an entity bean].
How can I see what is going on here?
If we are using IntelliJ Idea and open .class files IntelliJ will decompile them. We will see the GETFIELD/PUTFIELD code is replaced with the methods like _ebean_get_name() when we look at the decompiled classes.
This view of the decompiled classes will not show synthetic methods, and by default methods added by the ebean enhancement are synthetic. To view the methods and code that the ebean enhancement is adding to entity classes we need to turn that off using synthetic: false.
In the src/main/resources/ebean.mf add synthetic: false like:
synthetic: false
entity-field-access: true
Now, if we look at enhanced entity classes via IntelliJ decompiler we will see those methods like _ebean_get_name() etc.
Maven
When using the maven plugin or maven tile then ebean enhancement will be done for main code in the process-classes lifecycle and in process-test-classes for test code.
mvn clean process-test-classes
Performing the above will clean, compile and apply ebean enhancement without running tests. This is a good way to get the enhancement applied to target/classes & target/test-classes ... which we then get IntelliJ to decompile.
Controlling IntelliJ ebean-agent version
If we want to control exactly which ebean-agent jar is used by the IntelliJ plugin we can:
Put a ebean-agent-X.jar into a ~/.ebean directory
Turn off the plugin via IntelliJ - Build - Ebean enhancement
Turn on the plugin via IntelliJ - Build - Ebean enhancement
The turning off/on is the trigger for the IntelliJ plugin to check for a ~/.ebean/ebean-agent-X.jar to use rather than the one it comes with.
We can write our entities using public fields and not have getters/setters/accessors like:
How to enable entity-field-access
This feature is not enabled by default. We need to explicitly turn it on to use it.
src/main/resources/ebean.mf
with aentity-field-access
entry like:entity-packages
that contain entity beans like:We don't need to do this when using query beans because the querybean-generator automatically adds a
META-INF/ebean-generated-info.mf
manifest file with theentity-packages
entry for us.What does this feature do?
Background:
_ebean_get_name()
and_ebean_set_name(String name)
and uses those methods (ok, there is a little more to it but yeah)Field access enhancement: What the Ebean enhancement does here is it replaces GETFIELD and PUTFIELD with method calls like
_ebean_get_name()
and_ebean_set_name(String name)
.For example:
What this means is that although it looks like we are using "field access / GETFIELD / PUTFIELD" etc the enhancement has changed it to use the methods that Ebean enhancement has added and these methods have all the interception support of dirty checking, lazy loading etc.
We have all the same functionality as if we were using getters/setters/accessors.
Another way to look at it
Ebean enhancement replaces GETFIELD/PUTFIELD calls with its own
_ebean_get_name()
_ebean_set_name(...)
methods. Normally, this is restricted to ONLY doing this replacement on the entity beans themselves.When using
entity-field-access
this replacement is extended to any application code.When should I use this feature?
Currently it's experimental but if you have a lot of entity beans and perhaps a lot of those are from and application perspective "read only" and they are generally "read write" for testing purposes - then you'd be motivated to trying out this feature.
Limitations
Today it works by assuming that classes in the
entity-packages
are in fact entities. If we have classes that are not entities in the entity packages and we also use field access on those classes that will not work [those GETFIELD/PUTFIELD calls will be changed to method calls like _ebean_get_name() but those methods will not exist as the type isn't an entity bean].How can I see what is going on here?
If we are using IntelliJ Idea and open .class files IntelliJ will decompile them. We will see the GETFIELD/PUTFIELD code is replaced with the methods like
_ebean_get_name()
when we look at the decompiled classes.This view of the decompiled classes will not show synthetic methods, and by default methods added by the ebean enhancement are synthetic. To view the methods and code that the ebean enhancement is adding to entity classes we need to turn that off using
synthetic: false
.In the
src/main/resources/ebean.mf
addsynthetic: false
like:Now, if we look at enhanced entity classes via IntelliJ decompiler we will see those methods like
_ebean_get_name()
etc.Maven
When using the maven plugin or maven tile then ebean enhancement will be done for main code in the
process-classes
lifecycle and inprocess-test-classes
for test code.mvn clean process-test-classes
Performing the above will clean, compile and apply ebean enhancement without running tests. This is a good way to get the enhancement applied to
target/classes
&target/test-classes
... which we then get IntelliJ to decompile.Controlling IntelliJ ebean-agent version
If we want to control exactly which
ebean-agent
jar is used by the IntelliJ plugin we can:ebean-agent-X.jar
into a~/.ebean
directoryThe turning off/on is the trigger for the IntelliJ plugin to check for a
~/.ebean/ebean-agent-X.jar
to use rather than the one it comes with.