I'm using JPA's entitymanager.find(T, pk) to find a record. This is in an existing app where entitymanager.find() is used successfully, but this is the first instance of using a composite primary key. Here is the entity class:
@Entity
@Table(name = "host_property", schema = "app")
@IdClass(HostPropertyPK.class)
public class HostProperty implements Serializable {
@Id
@Column(name = "host")
private String host_;
@Id
@Column(name = "name")
private String name_;
@Column(name = "value")
private String value_;
private static final long serialVersionUID = 1L;
/**
* Java Persistence requires a no-argument constructor. Private so that only
* JPA may use it.
*/
private HostProperty() {
}
/**
* Gets the associated host.
*
* @return String containing the host
*/
public String getHost() {
return host_;
}
/**
* Gets the property name.
*
* @return String containing the property name
*/
public String getName() {
return name_;
}
/**
* Gets the property value.
*
* @return String containing the property value
*/
public String getValue() {
return value_;
}
/**
* Gets the value as an int.
*
* @return int containing the value parsed as an int
*/
public int getIntValue() {
return Integer.parseInt(value_);
}
}
and the primary key class:
public class HostPropertyPK implements Serializable {
private static final long serialVersionUID = 1L;
@Column(name = "host")
private String host_;
@Column(name = "name")
private String name_;
/**
* Java Persistence requires a no-argument constructor. Private so that
* only JPA may use it.
*/
@SuppressWarnings("unused")
private HostPropertyPK() {
}
/**
* Creates a host property primary key.
*
* @param host String containing the host
* @param propertyName String containing the property name
*/
public HostPropertyPK(String host, String propertyName) {
this.host_ = host;
this.name_ = propertyName;
}
/**
* Gets the host of this primary key.
*
* @return String containing the host
*/
public String getHost() {
return host_;
}
/**
* Gets the property name of this primary key.
*
* @return String containing the property name
*/
public String getPropertyName() {
return name_;
}
@Override
public int hashCode() {
int code = 1;
code = 31 * code + (host_ == null ? 0 : host_.hashCode());
code = 31 * code +
(name_ == null ? 0 : name_.hashCode());
return code;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null) {
return false;
}
if (!(o instanceof HostPropertyPK)) {
return false;
}
HostPropertyPK other = (HostPropertyPK) o;
if (host_ == null) {
if (other.getHost() != null) {
return false;
}
} else if (!host_.equals(other.getHost())) {
return false;
}
if (name_ == null) {
if (other.getPropertyName() != null) {
return false;
}
} else if (!name_.equals(other.getPropertyName())) {
return false;
}
return true;
}
}
and the bean where I look up properties:
@Stateless
@Local(PropertyService.class)
@TransactionManagement(TransactionManagementType.CONTAINER)
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class PropertyServiceBean implements PropertyService {
@PersistenceContext(unitName="AppPersistence")
private EntityManager entityManager_;
@Override
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public HostProperty getHostProperty(String host, String propertyName) {
HostPropertyPK hostPropertyPK =
new HostPropertyPK(host, propertyName);
HostProperty prop = entityManager_.find(HostProperty.class, hostPropertyPK);
System.out.println("FOUND HOST PROPERTY : " + prop);
return prop;
}
}
The value of prop at the point of System.out.println is null. I can confirm that the entity manager is not null by the fact execution reaches this point and also because I can capture the underlying query using XRebel:
select
hostpr0_.host as host623_0_,
hostpr0_.name as name623_0_,
hostpr0_.value as value623_0_
from
app.host_property hostpr0_
where
hostpr0_.host = 'testhost'
and hostpr0_.name = 'testprop'
I've confirmed that this query indeed returns a single row. However, Hibernate doesn't ultimately return my object, but rather a null! What could cause Hibernate to be able to generate the correct query, execute it, but not map an object from it?