senleft (15) [Avatar] Offline
#1
From item 3.2.1 I knew that "This is a rule in JPA: if @Id is on a field, the JPA provider will access fields of the class directly".

I can't find this rule in JPA spec. According to JPA specification


2.3.1 Default Access Type


By default, a single access type (field or property access) applies to an entity hierarchy. The default access type of an entity hierarchy is determined by the placement of mapping annotations on the attributes of the entity classes and mapped superclasses of the entity hierarchy that do not explicitly specify an access type. An access type is explicitly specified by means of the Access annotation [6], as described in section 2.3.2



More over, I think the default access (FIELD - with mapping placement above the field) will not work for the nesting @Embeddable classes (more than one), if you using the Hibernate. For the proper mapping you need to explicitly specify the access type FIELD on @Embeddable classes. It's slightly different from JPA spec.


Am I right or wrong about default access implementation for the nesting @Embeddable classes (more than one) in the Hibernate ?


I have posted question and code examples on the SOF (http://stackoverflow.com/questions/18441222/issue-with-jpa-mapping-for-two-nested-embeddable), but still don't get any answers.

Message was edited by:
senleft
Christian Bauer (56) [Avatar] Offline
#2
Re: Default access type
"When field-based access is used, the object/relational mapping annotations for the entity class annotate the instance variables, and the persistence provider runtime accesses instance variables directly."

"All such classes in the entity hierarchy whose access type is defaulted in this way must be consistent in their placement of annotations on either fields or properties, such that a single, consistent default access type applies within the hierarchy."

The examples of the book show nested @Embeddable classes Address and City with field access in Hibernate.
senleft (15) [Avatar] Offline
#3
Re: Default access type
I have seen the @Embeddable classes Address and City example. And this is not I’m talking about.
This is example with one level nested @Embeddable class City.
I’m talking about two level nested example like next.
I make a little refactoring for example in org.jpwh.model.collections.bagofembeddables
I added the second level @Embeddable class ImageMetadata to class Image instead of sizeX, sizeY fields (without accessors to this fields).
In spite of consistent placement of annotations above fields Hibernate can’t make mapping for ImageMetadata class.
https://dl.dropboxusercontent.com/u/8384811/Misc/embeddable.jpg
However if you will place @Access(AccessType.FIELD) annotation to ImageMetada it solves this issue.

So consistent placement of annotations above fields do not guarantee Hibernate access to fields of the second level @Embeddable class ImageMetadata.

Could you check it please and say me if I wrong in my previous statement.

Below is the source code of example
@Embeddable
public class Image {

@Column(nullable = true) // Can be null if we have surrogate PK!
protected String title;

@Column(nullable = false)
protected String filename;

protected ImageMetadata imageMetadata;

public Image() { }

public Image(String title, String filename, int sizeX, int sizeY) {
this.title = title;
this.filename = filename;
imageMetadata = new ImageMetadata(sizeX, sizeY);
}
}
@Entity
public class Item {

@Id
@GeneratedValue(generator = Constants.ID_GENERATOR)
protected Long id;

@ElementCollection
@CollectionTable(name = "IMAGE")
@org.hibernate.annotations.CollectionId(
columns = @Column(name = "IMAGE_ID"),
type = @org.hibernate.annotations.Type(type = "long"),
generator = Constants.ID_GENERATOR)
protected Collection<Image> images = new ArrayList<Image>();

public Long getId() {
return id;
}

public Collection<Image> getImages() {
return images;
}

// ...
}
@Embeddable
public class ImageMetadata {

protected int sizeX;
protected int sizeY;

public ImageMetadata() {}

public ImageMetadata(int sizeX, int sizeY) {
this.sizeX = sizeX;
this.sizeY = sizeY;
}
}
Christian Bauer (56) [Avatar] Offline
#4
Re: Default access type
The difference here is not the level of nesting but simply that one "inheritance" of access type is through a collection and the other one isn't. This looks indeed like a bug in Hibernate and I'll file a report.

Violates 2.3.3 of JPA 2.1:

"The access type of an embeddable class is determined by the access type of the entity class, mapped superclass, or embeddable class in which it is embedded (including as a member of an element collection) independent of whether the access type of the containing class has been explicitly specified or defaulted."
senleft (15) [Avatar] Offline
#5
Re: Default access type
Thank you very much!
May be it need to paraphrase statement "This is a rule in JPA: if @Id is on a field, the JPA provider will access fields of the class directly" as current JPA spec version tell nothing about this (or may be I couldn't find it).
Christian Bauer (56) [Avatar] Offline
#6
Re: Default access type
It's a simplification of the implied rules: The only required property-level annotation is @Id. If any property-level annotation is on a field, the others must be on fields and field access is the default. My rule is easier to learn and remember.