JBoss marshalling fail if java.util.concurrent.PriorityBlockingQueue is used in custom objects which need to be serialized in EAP

Solution Verified - Updated

Environment

  • Red Hat JBoss Enterprise Application Platform (EAP)
    • 6.4
    • 7.0

Issue

  • java.util.concurrent.PriorityBlockingQueue implements Serializable from the API but if object should be serialized for an EAP application it throws a NullPointerException with the cause like below.
ERROR [stderr] (EJB default - 2) Caused by: java.lang.NullPointerException
ERROR [stderr] (EJB default - 2) 	at java.util.concurrent.PriorityBlockingQueue.readObject(PriorityBlockingQueue.java:943)
ERROR [stderr] (EJB default - 2) 	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
ERROR [stderr] (EJB default - 2) 	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
ERROR [stderr] (EJB default - 2) 	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
ERROR [stderr] (EJB default - 2) 	at java.lang.reflect.Method.invoke(Method.java:498)
ERROR [stderr] (EJB default - 2) 	at org.jboss.marshalling.reflect.SerializableClass.callReadObject(SerializableClass.java:307)

Resolution

The Bug "BMAR-195 - SerializingCloner.clone of PriorityBlockingQueue causes NullPointerException" is tracked for EAP6 and EAP 7 will be fixed in future releases.

Apply the latest cumulative patch. Fixed in EAP 6.4 CP16 or later and EAP 7.0 CP8 or later

Root Cause

This content is not included.6.4 BZ 1445480
Content from issues.jboss.org is not included.7.0 JBEAP-10536

There is something unusual in how java.util.concurrent.PriorityBlockingQueue serialization works, it is implementing read/writeObject and the end of writeObject() it is setting the field q to null. This seems a bug in JBoss Marshalling where it was calling prepareFields twice, q was set the first time prepareFields was called but then the second time PriorityBlockingQueue had set it to null thus causing the NPE.

  • SerializingCloner.clone called on PriorityBlockingQueue
  • PriorityBlockingQueue writeObject is putting a value into q and then invoking defaultWriteObject which I think should write the field q value
  • it then sets q back to null
  • then back to SerializingCloner.clone it is cloning cloneFields where possibly it is setting q to null?
    Which would mean the field q is not set when readObject is invoked on PriorityBlockingQueue resulting in the NPE

The related code look like followed:
SerializingCloner.clone

        if (origInfo.hasWriteObject()) {
            final Queue<Step> steps = new ArrayDeque<Step>();
            final StepObjectOutputStream stepObjectOutputStream = createStepObjectOutputStream(orig, fields, steps);
            origInfo.callWriteObject(orig, stepObjectOutputStream);
            stepObjectOutputStream.flush();
            stepObjectOutputStream.doFinish();
            prepareFields(orig, fields);
            cloneFields(fields);
            if (cloneInfo.hasReadObject()) {
                cloneInfo.callReadObject(clone, createStepObjectInputStream(clone, cloneInfo, fields, steps));
            } else {
                storeFields(cloneInfo, clone, fields);
            }

PriorityBlockingQueue:

    private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException {
        lock.lock();
        try {
            // avoid zero capacity argument
            q = new PriorityQueue<E>(Math.max(size, 1), comparator);
            q.addAll(this);
            s.defaultWriteObject();
        } finally {
            q = null;
            lock.unlock();
        }
    }
Components
Category

This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.