javahibernatejakarta-eejpa-2.0type-mismatch

"org.hibernate.TypeMismatchException: Provided id of the wrong type" when using @OneToOne for a bi-directional relation


I don't succeed in using @OneToOne when the composite primary key is the same in both classes:

@Entity
public class One implements Serializable {
    private static final long serialVersionUID = 1L;
    @EmbeddedId
    private OnePK onePK;
    @OneToOne(cascade = CascadeType.ALL, mappedBy = "one")
    private Two two;
    //... constructors, getters and setters
}

@Entity
public class Two implements Serializable {
    private static final long serialVersionUID = 1L;
    @EmbeddedId
    private TwoPK twoPK;
    @JoinColumns({
        @JoinColumn(name = "P_ID", referencedColumnName = "P_ID", insertable = false, updatable = false),
        @JoinColumn(name = "L_ID", referencedColumnName = "L_ID", insertable = false, updatable = false)})
    @OneToOne(optional = false)
    private One one;
    //... constructors, getters and setters
}

@Embeddable
public class OnePK implements Serializable {
    @Basic(optional = false)
    @Column(name = "P_ID")
    private BigInteger dId;
    @Basic(optional = false)
    @Column(name = "L_ID")
    private BigInteger lId;
    //... constructors, getters and setters
}

@Embeddable
public class TwoPK implements Serializable {
    @Basic(optional = false)
    @Column(name = "P_ID")
    private BigInteger dId;
    @Basic(optional = false)
    @Column(name = "L_ID")
    private BigInteger lId;
    //... constructors, getters and setters
}

When I use the source code above as is, I get:

12:56:04,021 WARNING [org.apache.cxf.phase.PhaseInterceptorChain] (default task-83) Application {http://services.webservices.*****.******.com/}ObjectManagerService#{http://services.webservices.*****.******.com/}getAllObjects has thrown exception, unwinding now: org.apache.cxf.interceptor.Fault: java.lang.IllegalArgumentException: org.hibernate.TypeMismatchException: Provided id of the wrong type for class com.******.*****..********.Two. Expected: class com.******.*****..********.TwoPK, got class com.******.*****.**.********.OnePK at org.apache.cxf.service.invoker.AbstractInvoker.createFault(AbstractInvoker.java:162) at org.apache.cxf.jaxws.AbstractJAXWSMethodInvoker.createFault(AbstractJAXWSMethodInvoker.java:267) at

When I use the same class (OnePK) as the primary key of both classes (One and Two), I get:

11:44:35,735 WARNING [org.apache.cxf.phase.PhaseInterceptorChain] (default task-83) Interceptor for {http://services.webservices.*****.******.com/}ObjectManagerService#{http://services.webservices.*****.******.com/}getAllObjects has thrown exception, unwinding now: org.apache.cxf.interceptor.Fault: Marshalling Error: A cycle is detected in the object graph. This will cause infinitely deep XML : One[ onePK=OnePK[ dId=3151, lId=426 ] ] -> Two[ twoPK=OnePK[ dId=3151, lId=426 ] ] -> One[ onePK=OnePK[ dId=3151, lId=426 ] ] at org.apache.cxf.jaxb.JAXBEncoderDecoder.marshall(JAXBEncoderDecoder.java:266) at org.apache.cxf.jaxb.io.DataWriterImpl.write(DataWriterImpl.java:238) at org.apache.cxf.interceptor.AbstractOutDatabindingInterceptor.writeParts(AbstractOutDatabindingInterceptor.java:118) at

Using @PrimaryKeyJoinColumns didn't help, I used this answer and this tutorial, I got the same error messages. Using @MapsId didn't help, I got "org.hibernate.exception.GenericJDBCException: could not prepare statement". Maybe the root cause is this unfixed bug of Hibernate. The only workaround that I've found consists in removing the very first occurrence of @OneToOne and the field "two" in the class "One" but the instance of Two contained by an instance of One no longer gets deleted when I delete this instance of One, that's why I used CascadeType.ALL.

This JPA source code is auto-generated by Netbeans 8. I'm a bit out of options. Is there a way of making it work correctly? Is it really a limitation of Hibernate? Is there another implementation of JPA handling this case correctly?


Solution

  • At first, I increased the TTL connection timeout in Oracle UCP by calling this method in order to get rid of the GenericJDBCException. Some requests were taking too much time to execute whereas the time allowed to keep a connection in use was too low.

    Secondly, I used the same class named OnePK as the primary key of both classes One and Two.

    Thirdly, I added @XmlTransient into the class Two before the method getOne() in order to fix the cycle in the XML serialization.

    Fourthly, I modified my managers so that they call Two.setOne(final One one) in order to expose complete objects (instances of Two) for the source code calling the persistence layer without using the web services.

    At last, I fixed some similar cases but with simpler primary keys composed of only one column by using @MapsId.