I’m sure I’m doing something obviously wrong, but I’m not sure what so any help appreciated. I have a very simple case of CompositeUserType.
An entity…
@Entity
@Table(name = "parent_entity")
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class ParentEntity {
private Long id;
private String color;
private TargetEmbedded child;
public ParentEntity () {
}
public ParentEntity (String color, TargetEmbedded child) {
this.color = color;
this.child = child;
}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", unique = true, nullable = false, updatable = false)
public synchronized Long getId () {
return id;
}
public synchronized void setId (Long id) {
this.id = id;
}
@Column(name = "color", length = 25, updatable = false, nullable = false)
public String getColor () {
return color;
}
public void setColor (String color) {
this.color = color;
}
@Embedded
@AttributeOverride(name = "a", column = @Column(name = "a", nullable = false))
@AttributeOverride(name = "b", column = @Column(name = "b", nullable = false))
@AttributeOverride(name = "c", column = @Column(name = "c", nullable = false))
@CompositeType(TargetEmbeddedCompositeUerType.class)
public TargetEmbedded getChild () {
return child;
}
public void setChild (TargetEmbedded child) {
this.child = child;
}
}
An embedded to be wrapped in a user type…
public class TargetEmbedded {
private String encoded;
public TargetEmbedded () {
}
public TargetEmbedded (String encoded) {
this.encoded = encoded;
}
public String getEncoded () {
return encoded;
}
public void setEncoded (String encoded) {
this.encoded = encoded;
}
}
The user type…
public class TargetEmbeddedCompositeUerType implements CompositeUserType<TargetEmbedded> {
@Override
public boolean isMutable () {
return false;
}
@Override
public Class<?> embeddable () {
return TargetedEmbeddedMapper.class;
}
@Override
public Class<TargetEmbedded> returnedClass () {
return TargetEmbedded.class;
}
@Override
public boolean equals (TargetEmbedded x, TargetEmbedded y) {
return Objects.equals(x, y);
}
@Override
public int hashCode (TargetEmbedded x) {
return Objects.hashCode(x);
}
@Override
public TargetEmbedded deepCopy (TargetEmbedded value) {
return value;
}
@Override
public Serializable disassemble (TargetEmbedded value) {
return (Serializable)value;
}
@Override
public TargetEmbedded assemble (Serializable cached, Object owner) {
return (TargetEmbedded)cached;
}
@Override
public TargetEmbedded replace (TargetEmbedded detached, TargetEmbedded managed, Object owner) {
return detached;
}
@Override
public Object getPropertyValue (TargetEmbedded component, int property)
throws HibernateException {
if (component == null) {
return null;
} else {
String[] abc = component.getEncoded().split("-", -1);
// alphabetical
return switch (property) {
case 0 -> abc[0];
case 1 -> abc[1];
case 2 -> abc[2];
default -> null;
};
}
}
@Override
public TargetEmbedded instantiate (ValueAccess valueAccess, SessionFactoryImplementor sessionFactory)
throws HibernateException {
Object[] values = valueAccess.getValues();
if (values.length == 3) {
Integer a = (Integer)values[0];
Integer b = (Integer)values[0];
Integer c = (Integer)values[0];
return new TargetEmbedded(((a == null) ? "0" : a.toString()) + "-" + ((b == null) ? "0" : b.toString()) + "-" + ((c == null) ? "0" : c.toString()));
}
return null;
}
public static class TargetedEmbeddedMapper {
private Integer a;
private Integer b;
private Integer c;
}
}
The specifics don’t really matter except that we have fields in the database row that need to be wrapped and unwrapped into some other type defined in the entity. My problems is that on a simple initial insert…
@Test
public void hhhTest123 () {
EntityManager entityManager = entityManagerFactory.createEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
entityManager.merge(new ParentEntity("purple", new TargetEmbedded("1-2-3")));
entityManager.flush();
transaction.commit();
entityManager.close();
}
…Hibernate 6, specifically…
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-core</artifactId>
<version>6.4.4.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate.common</groupId>
<artifactId>hibernate-commons-annotations</artifactId>
<version>6.0.6.Final</version>
</dependency>
…produces this sql…
Hibernate:
insert
into
parent_entity
(color)
values
(?)
…which ignores the embedded type entirely, and neither getPropertyVaalue() nor instatiate() is ever called, the embedded type’s fields are not added to the insert, and of course it errors.
What have I missed? How do I get that insert to include the fields from the TargetEmbedded?