77 lines
2.4 KiB
Java
Executable File
77 lines
2.4 KiB
Java
Executable File
package com.ankurm.hibernatedemo.persistenceannotations;
|
|
|
|
import jakarta.persistence.Access;
|
|
import jakarta.persistence.AccessType;
|
|
import jakarta.persistence.Column;
|
|
import jakarta.persistence.Entity;
|
|
import jakarta.persistence.GeneratedValue;
|
|
import jakarta.persistence.Id;
|
|
import jakarta.persistence.Transient;
|
|
|
|
/**
|
|
* Default access is FIELD (because {@code @Id} is annotated on the field). One property,
|
|
* {@code computedLabel}, is explicitly switched to PROPERTY access via {@code @Access} on its
|
|
* getter, with a derivation the FIELD side does not know about. This reproduces the classic
|
|
* "mixed access silently reads the wrong value" symptom: a raw field mutation is invisible to
|
|
* Hibernate once a property is PROPERTY-access, and vice versa.
|
|
*
|
|
* <p>Docs: docs/05-jpa-persistence-annotations.md, Topic 2.
|
|
*/
|
|
@Entity
|
|
public class MixedAccessEntity {
|
|
|
|
@Id
|
|
@GeneratedValue
|
|
private Long id;
|
|
|
|
private String rawValue;
|
|
|
|
// FIELD access is the entity default (because @Id is on a field). This backing field is
|
|
// deliberately never read directly by Hibernate for the "label" property -- only the
|
|
// PROPERTY-access getter below is.
|
|
@Transient
|
|
private int getterCallCount = 0;
|
|
|
|
public MixedAccessEntity() {
|
|
}
|
|
|
|
public MixedAccessEntity(String rawValue) {
|
|
this.rawValue = rawValue;
|
|
}
|
|
|
|
public Long getId() {
|
|
return id;
|
|
}
|
|
|
|
public String getRawValue() {
|
|
return rawValue;
|
|
}
|
|
|
|
public void setRawValue(String rawValue) {
|
|
this.rawValue = rawValue;
|
|
}
|
|
|
|
/**
|
|
* Explicitly PROPERTY access: Hibernate calls this getter (not a field read) to determine
|
|
* the persisted value for the "computedLabel" mapped property.
|
|
*/
|
|
@Access(AccessType.PROPERTY)
|
|
@Column(name = "computed_label")
|
|
public String getComputedLabel() {
|
|
getterCallCount++;
|
|
return rawValue == null ? null : rawValue.toUpperCase();
|
|
}
|
|
|
|
// Hibernate's default PROPERTY-access strategy REQUIRES a setter even for a logically
|
|
// read-only derived column -- omitting it throws PropertyNotFoundException at boot
|
|
// ("Could not locate setter method for property 'computedLabel'"). This setter is a
|
|
// deliberate no-op: it exists purely to satisfy that requirement.
|
|
public void setComputedLabel(String ignored) {
|
|
// no-op: computedLabel is derived from rawValue, never written directly
|
|
}
|
|
|
|
public int getGetterCallCount() {
|
|
return getterCallCount;
|
|
}
|
|
}
|