I am migrating some classes in a Hibernate hbm.xml file to JPA annotations.
We have an embeddable class Address that is used in several places. Each place uses a different subset of the properties in Address.
(getters/setters omitted for brevity)
@Embeddable
public class Address {
  String email;
  String address;
  String city; 
  String state;
  String zip;
  String country;
}
@Entity
@Table(name="customer")
public class Customer {
  @Embedded
  @AttributeOverrides({
    @AttributeOverride(name="address", column=@Column(name="ship_addr"),
    @AttributeOverride(name="city", column=@Column(name="ship_city"),
    @AttributeOverride(name="state", column=@Column(name="ship_state"),
    @AttributeOverride(name="zip", column=@Column(name="ship_zip"),
    @AttributeOverride(name="country", column=@Column(name="ship_country")
  })
  Address shippingAddress;
  @Embedded
  @AttributeOverrides({
    @AttributeOverride(name="address", column=@Column(name="bill_addr"),
    @AttributeOverride(name="city", column=@Column(name="bill_city"),
    @AttributeOverride(name="state", column=@Column(name="bill_state"),
    @AttributeOverride(name="zip", column=@Column(name="bill_zip")
  })
  Address billingAddress;
}
Note that in this contrived example, shippingAddress uses Address.country, but billingAddress does not; and neither of them use Address.email.
The problem is that Hibernate is inferring @Column tags for any column where I haven't explicitly provided one.
I tried adding @Transient to all the Address fields, but it appears that @AttributeOverride does not trump @Transient.
Is there any workaround for this?
My advice would be to create a new entity called PartialAddress/NationalAddress/BillingAddress. This would be used only for the JPA mapping, and not exposed on the Customer interface:
private PartialAddress billingAddress;
public Address getBillingAddress() {
    return billingAddress.toAddress();
}
Otherwise, I have come up with a somewhat ugly workaround for this problem, maybe it will work for you as well. Instead of mapping the field to a real column, I return a SQL null constant:
@Embedded
@AttributeOverrides({
    @AttributeOverride(name="address", column=@Column(name="bill_addr"),
    @AttributeOverride(name="city", column=@Column(name="bill_city"),
    @AttributeOverride(name="state", column=@Column(name="bill_state"),
    @AttributeOverride(name="zip", column=@Column(name="bill_zip"),
    @AttributeOverride(name="country", column=@Column(name="bill_id + null"),
})
Address billingAddress;
I'm using Oracle and EclipseLink, works on Hibernate 3.6 as well. And I've only tested it on read-only objects. Though, theoretically, setting the insertable and updatable attributes to false should be enough.
I don't think it is possible with annotations to "ignore" a field from address in your embedded objects.
A workaround is to create a base type Address without email and an ExtendedAddress (subclass of Address) with the field email.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With