I am not very experienced with JPA and was curious if the following is possible.
Say I have a class Project as follows:
#Entity
public class Project {
#Id
private String projectCode;
private String departmentId;
/*
* Is something like this possible with JPA?
*/
if (departmentId == null) {
#JoinColumn(name = "projectCode", referencedColumnName = "assignedProject")
} else {
#JoinColumn(name = "departmentId", referencedColumnName = "id")
}
#OneToMany(targetEntity = Employee.class)
private List<Employee> contributors;
// getters/setters
}
So I would like to populate the contributors list based on the presence of departmentId.
Is this possible with JPA? Or will I have to specify two List<Employee> fields, mapped by both variables, and preform proper checks within my application logic?
Thanks for your help.
/*
* Is something like this possible with JPA?
*/
if (departmentId == null) {
#JoinColumn(name = "projectCode", referencedColumnName = "assignedProject")
} else {
#JoinColumn(name = "departmentId", referencedColumnName = "id")
}
No, this isn't possible with JPA and you'll be glad that it isn't.
You can achieve what you want by using inheritance in Java. Begin by creating an abstract entity that contains all the common fields of your table. Then you can create an entity subclass with a projectCode attribute and another entity subclass with a departmentId attribute.
At the RDBMS level, for a simple object model like the one we just built, a single table can be mapped. In the abstract entity, you would annotate as follows to achieve this:
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "DTYPE", discriminatorType = STRING, length = 1)
#DiscriminatorValue("?")
#Entity
public abstract class Project {
:
:
}
#DiscriminatorValue("P")
public class ProjectCodeProject extends Project {
:
:
}
Remember that RDBMS has no knowledge or notion of inheritance. Inheritance exists only on the Java side. In the database, inheritance is represented by metadata. The "Discriminator" is a special column (here named "DTYPE") that appears in your database table that informs JPA which subclass a particular column represents. In the above, the code "P" was chosen to represent database records that have a PROJECTCODE attribute rather than a DEPARTMENTID attribute.
Using a class hierarchy like this would enable you to have a table whose rows can have either a departmentId or a projectCode as an attribute (not both). Because rows of the table are all Projects, developing common logic in Java to work with the subtypes ought to be relatively straightforward.
Related
I'm using Hibernate with Spring Boot and JPA, and have a business requirement to retrieve and combine in to a single paged response data that is stored in four different tables in the DB.
Let's call the first two tables "tblCredits", containing Credits, and "tblDebits", containing Debits. For our purposes, those two tables are IDENTICAL - same column names, same column types, same ID fields, everything. And my endpoint is supposed to be able to return a combined list of both Credits and Debits, with the ability to search/sort by any/all of the fields being returned, and with paging.
If I controlled that DB, I would simply merge the two tables in to a single table, or create a view or stored proc which did that for me, but this is a legacy DB used by other applications which I can't modify in any way, so that's not an option.
If I didn't have to sort and page, I could just create two completely independent entities, create a separate Spring Data JPA repository for each entity, query the two repositories separately, and then just combine the results in my own code. But paging the combined results especially would get very hairy, I don't want to have to implement the merged paging logic myself unless I absolutely have to. Ideally I should be able to get JPA to handle all of that for me out-of-the-box.
I have been able achieve this first step for these first two tables using an abstract class declared as an Entity with InheritanceType.TABLE_PER_CLASS, like this:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class AbstractCreditDebitEntity {
/* literally all my properties and ID and column mappings here
...
*/
}
And then two concrete classes which extend that abstract entity and simply specify the two different table mappings, have no class-specific properties or column mappings at all:
#Entity
#Table(name = "tblCredits")
public final class Credit extends AbstractCreditDebitEntity {
//Literally nothing inside this class
}
#Entity
#Table(name = "tblDebits")
public final class Debit extends AbstractCreditDebitEntity {
//Literally nothing inside this class
}
So far so good, this works great, I am able to create a Spring JPA Repository on the AbstractCreditDebitEntity entity, under the hood that generates a union query on the two tables, and I am able to get back records from both tables in a single query, with appropriate paging and sorting. (The performance issues around union queries don't concern me at the moment.)
However, where I'm getting tripped up is on the next step, when I incorporate the additional two tables. tblCredits has a one-to-many relationship to tblCreditLineItems, and tblDebits has a one-to-many relationship to tblDebitLineItems. Again, tblCreditLineItems and tblDebitLineItems are IDENTICAL tables, from our perspective - same column names, same column types, same ID fields, everything.
So I can follow the same pattern as before for those sub-entities:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class AbstractCreditDebitLineItemEntity {
/* literally all my properties and ID and column mappings here
...
*/
}
#Entity
#Table(name = "tblCreditLineItems")
public final class CreditLineItem extends AbstractCreditDebitLineItemEntity {
//Literally nothing inside this class
}
#Entity
#Table(name = "tblDebitLineItems")
public final class DebitLineItem extends AbstractCreditDebitLineItemEntity {
//Literally nothing inside this class
}
But now I need to create the mappings between the Credit/Debit entities and CreditLineItem/DebitLineItem entities. And this is where I'm struggling. Because I need to be able to filter which specific Credit/Debit entities I return based on the values of properties inside their associated CreditLineItem/DebitLineItem entities, I need a bidirectional mapping between the two entities, and I've been unable to get that working successfully.
Here's how far I've gotten so far. First the three Credit/Debit entities with the OneToMany mapping to their associated CreditLineItem/DebitLineItem entities:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class AbstractCreditDebitEntity {
/* literally all my properties and ID and column mappings here
...
*/
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(
name = "MyIdColumnName",
referencedColumnName = "MyIdColumnName"
)
public abstract List<AbstractCreditDebitLineItemEntity> getCreditDebitLineItems();
public abstract void setCreditDebitLineItems(List<AbstractCreditDebitLineItemEntity> items);
}
#Entity
#Table(name = "tblCredits")
public final class Credit extends AbstractCreditDebitEntity {
private List<CreditLineItem> creditDebitLineItems;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, targetEntity = CreditLineItem.class)
#JoinColumn(
name = "MyIdColumnName",
referencedColumnName = "MyIdColumnName"
)
#Override
public List<AbstractCreditDebitLineItemEntity> getCreditDebitLineItems() {
return Optional.ofNullable(creditDebitLineItems).stream()
.flatMap(List::stream)
.filter(value -> AbstractCreditDebitLineItemEntity.class.isAssignableFrom(value.getClass()))
.map(AbstractCreditDebitLineItemEntity.class::cast)
.collect(Collectors.toList());
}
#Override
public void setCreditDebitLineItems(List<AbstractCreditDebitLineItemEntity> items) {
creditDebitLineItems = Optional.ofNullable(items).stream()
.flatMap(List::stream)
.filter(value -> CreditLineItem.class.isAssignableFrom(value.getClass()))
.map(CreditLineItem.class::cast)
.collect(Collectors.toList());
}
}
#Entity
#Table(name = "tblDebits")
public final class Debit extends AbstractCreditDebitEntity {
private List<DebitLineItem> creditDebitLineItems;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, targetEntity = DebitLineItem.class)
#JoinColumn(
name = "MyIdColumnName",
referencedColumnName = "MyIdColumnName"
)
#Override
public List<AbstractCreditDebitLineItemEntity> getCreditDebitLineItems() {
return Optional.ofNullable(creditDebitLineItems).stream()
.flatMap(List::stream)
.filter(value -> AbstractCreditDebitLineItemEntity.class.isAssignableFrom(value.getClass()))
.map(AbstractCreditDebitLineItemEntity.class::cast)
.collect(Collectors.toList());
}
#Override
public void setCreditDebitLineItems(List<AbstractCreditDebitLineItemEntity> items) {
creditDebitLineItems = Optional.ofNullable(items).stream()
.flatMap(List::stream)
.filter(value -> DebitLineItem.class.isAssignableFrom(value.getClass()))
.map(DebitLineItem.class::cast)
.collect(Collectors.toList());
}
}
And then the three CreditLineItem/DebitLineItem entities with their ManyToOne mappings back to the Credit/Debit entities:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class AbstractCreditDebitLineItemEntity {
/* literally all my properties and ID and column mappings here
...
*/
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(
name = "MyIdColumnName",
referencedColumnName = "MyIdColumnName",
updatable = false,
insertable = false)
public abstract AbstractCreditDebitEntity getCreditDebit();
public abstract void setCreditDebit(AbstractCreditDebitEntity creditDebitEntity);
}
#Entity
#Table(name = "tblCreditLineItems")
public final class CreditLineItem extends AbstractCreditDebitLineItemEntity {
private Credit creditDebit;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(
name = "MyIdColumnName",
referencedColumnName = "MyIdColumnName",
updatable = false,
insertable = false)
#Override
public Credit getCreditDebit() {
return creditDebit;
}
#Override
public void setCreditDebit(AbstractCreditDebitEntity creditDebitEntity) {
creditDebit =
Optional.ofNullable(creditDebitEntity)
.filter(value -> Credit.class.isAssignableFrom(value.getClass()))
.map(Credit.class::cast)
.orElse(throw new RuntimeException());
}
}
#Entity
#Table(name = "tblDebitLineItems")
public final class DebitLineItem extends AbstractCreditDebitLineItemEntity {
private Debit creditDebit;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(
name = "MyIdColumnName",
referencedColumnName = "MyIdColumnName",
updatable = false,
insertable = false)
#Override
public Debit getCreditDebit() {
return creditDebit;
}
#Override
public void setCreditDebit(AbstractCreditDebitEntity creditDebitEntity) {
creditDebit =
Optional.ofNullable(creditDebitEntity)
.filter(value -> Debit.class.isAssignableFrom(value.getClass()))
.map(Debit.class::cast)
.orElse(throw new RuntimeException());
}
}
This code compiles, however... when in my automated tests I try to persist one of my Credit entities (I use a simple H2 database for my automated tests), I get the following error:
2021-04-02 13:53:52 [main] DEBUG org.hibernate.SQL T: S: - update AbstractCreditDebitLineItemEntity set MyIdColumnName=? where ID=?
2021-04-02 13:53:52 [main] DEBUG o.h.e.jdbc.spi.SqlExceptionHelper T: S: - could not prepare statement [update AbstractCreditDebitLineItemEntity set MyIdColumnName=? where ID=?]
org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "ABSTRACTCREDITDEBITLINEITEMENTITY" does not exist
It appears to be trying to persist based on the #OneToMany mapping from my AbstractCreditDebitEntity class to my AbstractCreditDebitLineItemEntity. Which, since it's an abstract class with InheritanceType.TABLE_PER_CLASS, has no table specified for it, so it assumes the table it needs to persist to has the same name as the class.
What I wanted to happen here is for the #OneToMany mapping on the concrete getter in the Credit subclass, which specifies its targetEntity as the concrete CreditLineItem.class, to essentially override/replace the #OneToMany mapping on its parent abstract class. But it seems the mapping on the concrete class gets completely ignored?
I could remove the #OneToMany mapping from the AbstractCreditDebitEntity class entirely, and only define that mapping in the two concrete Credit/Debit entities that extend it. That makes the persistence error go away, and 90% of my test cases pass... but in that case when I try to filter or sort the results coming back from the combined AbstractCreditDebitEntity Spring Data JPA repository based on one of the fields that only exists in the CreditLineItem/DebitLineItem sub-entity, the query fails due to the AbstractCreditDebitEntity no longer having any mapping to the AbstractCreditDebitLineItemEntity.
Is there any good way of resolving this problem, so that the OneToMany mapping from AbstractCreditDebitEntity to AbstractCreditDebitLineItemEntity still exists, but the knowledge that the Credit entity maps specifically to the CreditLineItem entity and the Debit entity maps specifically to the DebitLineItem entity is also maintained?
After a lot of experimentation, I found something that works for me.
Basically, rather than try to override the OneToMany mapping in the abstract entity class with the OneToMany mappings in the concrete entities, I had to make them completely separate mappings to completely different properties. Which means my concrete entities have two different collections of AbstractCreditDebitLineItemEntity, and some AbstractCreditDebitLineItemEntity objects will appear twice, in both collections. A bit wasteful in terms of memory/computation, but I'm okay with that, it works!
So here's what I ended up with:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class AbstractCreditDebitEntity {
/* literally all my properties and ID and column mappings here
...
*/
private List<AbstractCreditDebitLineItemEntity> creditDebitLineItems;
#OneToMany(fetch = FetchType.LAZY, targetEntity = AbstractCreditDebitLineItemEntity.class)
#JoinColumn(
name = "MyIdColumnName",
referencedColumnName = "MyIdColumnName",
updatable = false,
insertable = false
)
public List<AbstractCreditDebitLineItemEntity> getCreditDebitLineItems() {
return creditDebitLineItems;
}
public void setCreditDebitLineItems(List<AbstractCreditDebitLineItemEntity> items) {
creditDebitLineItems = items;
}
}
#Entity
#Table(name = "tblCredits")
public final class Credit extends AbstractCreditDebitEntity {
private List<CreditLineItem> creditLineItems;
#OneToMany(cascade = CascadeType.ALL, targetEntity = CreditLineItem.class)
#LazyCollection(LazyCollectionOption.FALSE)
#JoinColumn(
name = "MyIdColumnName",
referencedColumnName = "MyIdColumnName"
)
public List<CreditLineItem> getCreditLineItems() {
return creditLineItems;
}
#Override
public void setCreditDebitLineItems(List<CreditLineItem> items) {
creditLineItems = items;
}
}
With the exact same pattern repeated for the Debit entity.
This allows me to both:
persist, using the OneToMany mappings from the concrete Credit and Debit entities to the concrete CreditLineItem and DebitLineItem entities; and
do finds on the Spring Data JPA repository of AbstractCreditDebitEntity, using the the completely separate OneToMany mapping from that abstract entity to the AbstractCreditDebitLineItemEntity.
Not as clean as if I'd been able to override the OneToMany mapping in the abstract parent class with a more specific OneToMany mapping in the concrete child classes... but as I said, it works!
(The answer on this issue helped me know I needed to replace fetchType=FetchType.EAGER on my concrete OneToMany mappings with #LazyCollection(LazyCollectionOption.FALSE):
Hibernate throws MultipleBagFetchException - cannot simultaneously fetch multiple bags)
I'm having issues with defining a foreign key field within an entity. One specific thing that I can't find an answer to, is how to define such field but as a Long type, and not as that target entity type, and also set it up as ON DELETE CASCADE.
E.g.
#Entity
#Table(name = "user")
public class UserEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
}
and
#Entity
#Table(name = "address")
public class AddressEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#JoinColumn(
table = "user",
name = "user_id",
referencedColumnName = "id")
private Long userId;
}
This example works fine, but now one can't easily define this DELETE ON CASCADE for the userId field i.e. Address entity.
One specific thing that I can't find an answer to, is how to define
such field but as a Long type, and not as that target entity type, and
also set it up as ON DELETE CASCADE.
It stands to reason that you cannot find an answer, because JPA does not provide one. If you want JPA to manage relationships between entities, then you must define those relationships in the JPA way, with entities holding references to other entity objects and declaring appropriate relationship annotations.* And if you want cascading deletes in your persistence context then you definitely do want them to be managed / recognized by JPA, for any other kind of approach is likely to create problems involving the context falling out of sync with the underlying data store.
It's unclear what problem you are trying to solve by avoiding JPA-style relationship management, but I'm inclined to think that there must be a better way. For example, if you want to avoid requiring the persistence context to load the associated UserEntity whenever an AddressEntity is loaded, then you would define the relationship with a lazy fetch strategy:
#Entity
public class AddressEntity {
// ...
#OneToOne(optional = true, fetch = FetchType.LAZY)
private UserEntity user;
}
#Entity
public class UserEntity {
// ...
#OneToOne(optional = true, fetch = FetchType.LAZY, cascade = CascadeType.ALL,
mappedBy = user)
AddressType address;
}
(Do note, however, that FetchType.LAZY is a hint, not a constraint. The context might sometimes still load the user together with its address if that's convenient.)
If you want to get the associated user id from an address, then the best way to do so is to read it from the user:
// ...
public Long getUserId() {
return (user == null) ? null : user.getId();
}
That does require the UserEntity to define an accessible getId() method, but since you are using JPA field-based access, you do not need also to provide a setter, and you may give the method default access. Or you could just declare UserEntity.id such that it is directly accessible by AddressEntity.
On the other hand, if you want to provide for the user ID to be accessible without loading the user entity then instead of a method such as the above getUserId(), in addition to the relationship field you could define a persistent, read-only AddressEntity.userId field, mapped to the appropriate column. It must be read-only because the value of the id in the underlying data store will necessarily be managed via the entity relationship, so it cannot also be managed via this separate field. For example:
#Entity
public class AddressEntity {
// ...
#OneToOne(optional = true, fetch = FetchType.LAZY)
private UserEntity user;
#Column(name = "user_id", insertable = false, updatable = false, nullable = true)
public Long userId;
}
This is a brittle approach, and I do not recommend it. It will be prone to problems with the userId field falling out of sync with the user entity. That may be bearable for the usage you have in mind, but this sort of weirdness is fertile ground for future bugs.
*Side note: as far as I know or can determine, JPA does not define semantics for a #JoinColumn annotation on a non-relationship field such as in your original code. That doesn't mean that your particular persistence provider can't interpret it in a way that you characterize as "works fine", but at minimum you are on thin ice with that.
I have a MessengerData class which contains a list of resources. This my object MessengerData:
"messengerData":{
"fr":[
{
"messengerType":"ImageCategoryTitle",
"imageURL":"https://assets.pernod-ricard.com/uk/media_images/test.jpg"
}
"EN":[
{
"messengerType":"ImageCategoryTitle",
"imageURL":"https://assets.pernod-ricard.com/uk/media_images/test.jpg",
}
]
This is how I define my object MessengerData:
#Entity
public class MessengerData
{
#Basic
#Id
#GeneratedValue(generator = "notification-system-uuid")
#GenericGenerator(name = "notification-system-uuid", strategy = "uuid")
private String messengerDataId;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) /* , mappedBy = "idResource" */
#JoinTable(name = HemisTablesNames.MESSENGER_RESOURCES, joinColumns = #JoinColumn(name = "idResource"),
inverseJoinColumns = #JoinColumn(name = "messengerDataId"))
private Map<String, Set<Resource>> resources;
}
But I am getting this exception: Use of #OneToMany or #ManyToMany targeting an unmapped class: com.ubiant.hemis.type.MessengerData.resources[java.util.Set]
Could someone help me with this ?
Hibernate doesn't seem to support multimaps (that's what resources is) directly but you could provide your own custom type like described here: https://xebia.com/blog/mapping-multimaps-with-hibernate/ .
However, since your data seems to be Json anyway you could go one more step and directly map the resources as json, i.e. into a text column (or a json column if the db supports it): http://fabriziofortino.github.io/articles/hibernate-json-usertype/
We're doing something similar, which on an outline looks like this (this is a generic type, in most cases a more specific POJO will be better):
class JsonData extends HashMap<String, Object> { ... }
//JsonbUserType is a custom implementation based on code like the one linked above
class JsonDataUT extends JsonbUserType<JsonData > { ... }
Then in package-info.java of the package the user type is in we have this:
#TypeDefs ( {
#TypeDef ( name = "JsonDataUT ", typeClass = JsonDataUT.class, defaultForType = JsonData.class ),
...
})
package our.package;
And our entities then just contain this:
#Column( name = "data_column")
private JsonData data;
One advantage of this is that we don't have to bother with more complex mappings, especially if types are dynamic.
One (major) disadvantage, however, is that you can't use that property in query conditions since Hibernate wouldn't know how to filter in a json column (we're using Postgres so it would really be a jsonb typed column, hence the usertype name) and afaik there's not reasonable way to provide custom functions etc. to enable things like where data.someFlag is true in HQL.
I am working on hibernate 5 and implemented the ImplicitNamingStrategy interface. Among other methods, there are two methods called determinePrimaryKeyJoinColumnName(...) and determineJoinColumnName(...). In the java doc, it says about determinePrimaryKeyJoinColumnName:
Determine the column name related to {#link javax.persistence.PrimaryKeyJoinColumn}. In
* {#code hbm.xml} terms, this would be a {#code } defined for a {#code }
* or a {#code } (others?)
I annotated my joins with PrimaryKeyJoinColumn and the code works, however the names never get routed through determinePrimaryKeyJoinColumnName(...) but through determineJoinColumnName(...).
Am I wrong in believing this is a bug?
#PrimaryKeyJoinColumn can be used like #JoinColumn only for the #OneToOne mapping. In such situation an additional join column is not used and, of course, the name of such "not existing column" is not generated.
#PrimaryKeyJoinColumn can be used for an inheritance too. For an example
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
#DiscriminatorColumn(name = "someDiscriminator")
public class Customer {
#Id
#GeneratedValue
private Long customerPid;
#Column
private String customerName;
}
#Entity
#PrimaryKeyJoinColumn(name = "xxxYY")
public class ValuedCustomer extends Customer {
#Column
private String valuedCustomerName;
}
Hibernate will use xxxYY for a column name. But if you do not specify a name
#Entity
#PrimaryKeyJoinColumn
public class ValuedCustomer extends Customer {
#Column
private String valuedCustomerName;
}
}
Hibernate will not use determinePrimaryKeyJoinColumnName() to generate a name. So, looks like, it is a bug.
Hibernate calls determinePrimaryKeyJoinColumnName() only in one place Ejb3JoinColumn.java#L719. But I can't get in which situations this happens.
I have encountered such problems too, when try to implement an adapter of Hibernate 4 NamingStrategy for Hibernate 5. You can refer ImprovedNamingStrategy for Hibernate 5 for an additional notes.
And my try to implement Hibernate 5 Implicit Naming Strategy.
I have a generic Database structure which can store several user-defined records. For example, the main table is RECORD and the columns are STRING01, STRING02, [...], NUM01, NUM02 etc.
I know this is a bit weird, but it has advantages as well as disadvantages. However, this structure exists and can't be changed. Now I want to create some JPA classes.
First, I created an abstract class RECORD as follows (the Annotations are placed on the gettersthe example is just simplified):
#Entity
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="TYPE", discriminatorType=DiscriminatorType.STRING)
public abstract class Record {
#Id
private long id;
#Column(name="STRING01")
private String string01;
#Column(name="STRING02")
private String string02;
#Column(name="NUM01")
private BigDecimal num01;
}
Then, I created specific classes inherited from RECORD:
#Entity
#DiscriminatorValue("Person")
public class Person extends Record {
#Transient
public String getFirstName() {
return getString01();
}
public void setFirstName(String name) {
setString01(name);
}
#Transient
public BigDecimal getWeight() {
return getNum01();
}
public void setWeight(BigDecimal weight) {
setNum01(weight);
}
}
This works fine, as I can query RECORD for a PERSON's primary key (via EntityManager.find()) and get a Result as instance of PERSON. I can query for FirstName and Weight without having to know the generic column names.
However, if I write my own JPA Query like SELECT p FROM Person p WHERE p.firstName = 'Michael', it fails. firstName is transient, and here I have to use the generic name string01.
Is there some way of overriding the base class' attribute name in JPA? Maybe there's a vendor-specific solution (I'm using EclipseLink)?
You can try and map multiple attributes to the same column.
The additional attribute would then be annotated with #Column( name = "column name", insertable = false, updatable = false, nullable = false ).
Alternatively, you might be able to replace/enhance the JPQL resolver in order to internally map p.firstName to p.string01, but that would be EclipseLink specific, and I don't really know if that's even possible. Take this as just a hint what to look for.