OpenLiberty: Error on Injection, works on TomEE and Wildfly

SOLUTION:

I found the reason of the error, and it is NOT the problem with OpenLiberty. I did not specify any beans.xml, and with that, the bean-discovery-mode defaults to annotated.

Please refer to the following link:

By default, if you specify nothing and there is no beans.xml, the bean discovery mode of ‘annotated’ and not ‘all’ is assumed. (Oracle 2013)


While I was working on this blog, I encountered this error:

[INFO    ] DSRA8203I: Database product name : MySQL
[INFO    ] DSRA8204I: Database product version : 8.0.11
[INFO    ] DSRA8205I: JDBC driver name  : MySQL Connector/J
[INFO    ] DSRA8206I: JDBC driver version  : mysql-connector-java-8.0.11 (Revision: 6d4eaa273bc181b4cf1c8ad0821a2227f116fedf)
[INFO    ] CWWJP9990I: test/wsjpa:wsjar:file:/home/dwuysan/dev/appservers/wlp/usr/servers/test/apps/expanded/test.war/WEB-INF/lib/d9f2b261-b3c6-4001-8a61-0aaebe46aa99.jar!/_testPU login successful
[INFO    ] WELD-000900: 2.4.5 (Final)
[INFO    ] FFDC1015I: An FFDC Incident has been created: "org.jboss.weld.exceptions.DeploymentException: WELD-001408: Unsatisfied dependencies for type EntityManager with qualifiers @Default
  at injection point [BackedAnnotatedField] @Inject private id.co.lucyana.test.services.LogService.em
  at id.co.lucyana.test.services.LogService.em(LogService.java:0)
 com.ibm.ws.container.service.state.internal.ApplicationStateManager 31" at ffdc_18.06.21_14.11.27.0.log
[INFO    ] FFDC1015I: An FFDC Incident has been created: "com.ibm.ws.container.service.state.StateChangeException: org.jboss.weld.exceptions.DeploymentException: WELD-001408: Unsatisfied dependencies for type EntityManager with qualifiers @Default
  at injection point [BackedAnnotatedField] @Inject private id.co.lucyana.test.services.LogService.em
  at id.co.lucyana.test.services.LogService.em(LogService.java:0)
 com.ibm.ws.app.manager.module.internal.DeployedAppInfoBase 384" at ffdc_18.06.21_14.11.27.1.log
[INFO    ] CWWJP9990I: test/wsjpa:wsjar:file:/home/dwuysan/dev/appservers/wlp/usr/servers/test/apps/expanded/test.war/WEB-INF/lib/d9f2b261-b3c6-4001-8a61-0aaebe46aa99.jar!/_testPU logout successful
[ERROR   ] CWWKZ0002E: An exception occurred while starting the application test. The exception message was: com.ibm.ws.container.service.state.StateChangeException: org.jboss.weld.exceptions.DeploymentException: WELD-001408: Unsatisfied dependencies for type EntityManager with qualifiers @Default
  at injection point [BackedAnnotatedField] @Inject private id.co.lucyana.test.services.LogService.em
  at id.co.lucyana.test.services.LogService.em(LogService.java:0)

The two classes we need to focus on are:

package id.co.lucyana.test.util;

import javax.enterprise.inject.Produces;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

public class EntityManagerProducer {
    
    @PersistenceContext(unitName = "testPU")
    @Produces
    private EntityManager em;
}

AND

package id.co.lucyana.test.services;

import id.co.lucyana.test.entity.Log;
import java.util.Collection;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.persistence.EntityManager;

@Stateless
@LocalBean
public class LogService {

    @Inject
    private EntityManager em;
       
    public Collection<Log> getLogs() {
        return this.em.createNamedQuery(Log.FIND_ALL, Log.class).getResultList();
    }
}

The thing is, this approach is working on both TomEE and Wildfly.

Any thought?

P.S. I was following someone’s recommendation on the net, of using this approach previously, with the argument that if one should ever change the name of ‘unitName’, it can be done on one single spot. I couldn’t find the reference anymore. I am not sure if this is still a ‘good’ approach. I welcome any comment.

References

Oracle, 2013, ‘Default CDI Enablement in Java EE 7’, Oracle, accessed on 24 June 2018

Advertisements

The problem with JPA Composite primary keys and CascadeType.ALL

Following my previous blog here, I encountered another issue with the use of composite primary keys.

With JPA, we can specify the cascade of relationship to be CascadeType.ALL, so that when we persist the CUSTOMER, all of its PRODUCT are persisted too.

So, the code will be modified as follows:

CUSTOMER

package com.wordpress.dwuysan;

// imports omitted

@Entity
@Table(name = "customer")
public class Customer implements Serializable {
    @Id
    @Column(name = "customer_id")
    private String customerId;

    @OneToMany(
        fetch = FetchType.EAGER,
        mappedBy = "customer",
        cascade = CascadeType.ALL)
    private Set<Product> products = new HashSet<Product>();

    /* the rest of the code omitted */
}

During unit testing however, when executing the following lines:

    this.entityManager.persist(customer); // customer with child products here
    final Query query = this.entityManager.createQuery("FROM Customer cust");
    return query.getResultList(); // error here

And the error is:

javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: Could not execute JDBC batch update
	at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:637)
	at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:74)
	at com.wordpress.dwuysan.CustomerServiceBean(CustomerServiceBean.java:59)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:309)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)

SO, for now, I think I will use another ID for the PRODUCT. Would need to look for the underlying reason.

@JoinColumn is part of the composite primary keys

Whilst it is not very common (hmmm … , come to think of it, it may be quite common), there are cases where one would require the use of composite primary keys in JPA, but at the same time, one of the key is actually a foreign key to another parent table.

Let’s just say for example there are table CUSTOMER and PRODUCT (Smith 2007), in this case the PRODUCT uses composite primary key of PRIMARY KEY (customer_id, product_id).

In JPA, they are mapped as follows:

CUSTOMER

package com.wordpress.dwuysan;

// imports omitted

@Entity
@Table(name = "customer")
public class Customer implements Serializable {
    @Id
    @Column(name = "customer_id")
    private String customerId;

    @OneToMany(
        fetch = FetchType.EAGER,
        mappedBy = "customer")
    private Set<Product> products = new HashSet<Product>();

    /* the rest of the code omitted */
}

PRODUCTPK

package com.wordpress.dwuysan;

// imports omitted

@Embeddable
public class ProductPK implements Serializable {
    private String productId;
    private String customerId;

    /* the rest of the code omitted */
}

PRODUCT

package com.wordpress.dwuysan;

// imports omitted

@Entity
@Table(name = "product")
public class Product implements Serializable {

    @AttributeOverrides({
        @AttributeOverride(
            name = "customerId",
            column = @Column(name = "customer_id")),
        @AttributeOverride(
            name = "productId",
            column = @Column(name = "productId"))
    })
    private ProductPK productPK;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "customer_id")
    private Customer customer;
}

However, on compiling, I got the following error from JUnit:

Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: com.wordpress.dwuysan.Product column: customer_id (should be mapped with insert="false" update="false")
	at org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:652)
	at org.hibernate.mapping.PersistentClass.checkPropertyColumnDuplication(PersistentClass.java:674)
	at org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:696)
	at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:450)
	at org.hibernate.mapping.RootClass.validate(RootClass.java:192)
	at org.hibernate.cfg.Configuration.validate(Configuration.java:1108)

So, to resolve this, we need to modify the Product class to:

PRODUCT

package com.wordpress.dwuysan;

// imports omitted

@Entity
@Table(name = "product")
public class Product implements Serializable {

    @AttributeOverrides({
        @AttributeOverride(
            name = "customerId",
            column = @Column(name = "customer_id")),
        @AttributeOverride(
            name = "productId",
            column = @Column(name = "productId"))
    })
    private ProductPK productPK;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "customer_id", insertable = false, updatable = false)
    private Customer customer;
}

Reference:
Smith, J, 2007, ‘Composite Primary Keys’, accessed 22 February 2012.

org.hibernate.type.SerializationException and java.io.StreamCorruptedException: invalid stream header

Today, I encountered the following error when developing a few JPA entities.

Originally thrown as : java.io.StreamCorruptedException: invalid stream header: 52657175
	at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:782)
	at java.io.ObjectInputStream.(ObjectInputStream.java:279)
	at org.hibernate.util.SerializationHelper$CustomObjectInputStream.(SerializationHelper.java:252)
	at org.hibernate.util.SerializationHelper.deserialize(SerializationHelper.java:209)
Rethrown as : org.hibernate.type.SerializationException: could not deserialize
	at org.hibernate.util.SerializationHelper.deserialize(SerializationHelper.java:217)
	at org.hibernate.util.SerializationHelper.deserialize(SerializationHelper.java:240)
	at org.hibernate.type.SerializableType.fromBytes(SerializableType.java:82)
	at org.hibernate.type.SerializableType.get(SerializableType.java:39)
	at org.hibernate.type.NullableType.nullSafeGet(NullableType.java:163)
	at org.hibernate.type.NullableType.nullSafeGet(NullableType.java:154)
	at org.hibernate.loader.Loader.getKeyFromResultSet(Loader.java:1097)
	at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:565)
	at org.hibernate.loader.Loader.doQuery(Loader.java:701)
	at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:236)
	at org.hibernate.loader.Loader.loadCollection(Loader.java:1994)
	at org.hibernate.loader.collection.CollectionLoader.initialize(CollectionLoader.java:37)
	at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:566)
	at org.hibernate.event.def.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:64)
	at org.hibernate.impl.SessionImpl.initializeCollection(SessionImpl.java:1716)
	at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:344)
	at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:87)
	at org.hibernate.collection.AbstractPersistentCollection.readElementExistence(AbstractPersistentCollection.java:143)
	at org.hibernate.collection.PersistentSet.contains(PersistentSet.java:153)
	at com.yarris.consol.messagelistener.RequeueToIntegrationHandler.isAppropriateHandler(RequeueToIntegrationHandler.java:69)
	at com.yarris.consol.messagelistener.OrderBAMMessageListener.onMessage(OrderBAMMessageListener.java:90)
	at org.springframework.jms.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:561)
	at org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:498)
	at org.springframework.jms.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:467)
	at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.doReceiveAndExecute(AbstractPollingMessageListenerContainer.java:325)
	at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:243)
	at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1058)
	at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1050)
	at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:947)
	at java.lang.Thread.run(Thread.java:662)

Basically, I have two JPA entities, and they have @ManyToMany relationship.

First JPA entity:

public class Person implements Serializable {
    @Id
    @Column(name = "person_no")
    private Long personNo;

    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(
        name = "person_specialisation",
        joinColumns = 
            @JoinColumn(name = "person_no",
                referencedColumnName = "person_no"),
        inverseJoinColumns = 
            @JoinColumn(name = "specialisation_type", 
                referencedColumnName = "specialisation_type"))
    private Set<Specialisation> specs = new HashSet<Specialisation>();

    // ... rest of the code omitted
}

Second JPA entity:

public class Specialisation implements Serializable {
    @Id
    @Column(name = "specialisation_type")
    @Enumerated(EnumType.STRING)
    private SpecialisationType specialisationType;

    @ManyToMany(
        fetch = FetchType.LAZY,
        mappedBy = "specialisations")
    private Set<Person> persons = new HashSet<Person>

    // ... rest of the code omitted
}

SO, basically the finding is that enumeration cannot be used as Id. Some posts also suggest this cannot be done.

References:
Hibernate, 2010, ‘JPA Support of Enum as Primary Key’, accessed on 09 February 2012.
Bozho, 2010, ‘Using enum as id’, accessed on 09 February 2012.