surinder-insonix / datanucleus-appengine

Automatically exported from code.google.com/p/datanucleus-appengine
0 stars 0 forks source link

"java.lang.IllegalArgumentException: A collection of values is required" is thrown when using an unowned List #299

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
I am running app engine 1.7.1 with JPA 2 enabled and using @Unowned 
relationships. Below is the exception I get when using a List as my @OneToMany 
collection. This does NOT when using a Set, which is very strange. I tracked it 
down and it appears that during entity detatch it is trying to use a 
FilterPredicate to fetch the child entities using their keys. This List of 
entities is initially empty and appears to be causing a problem. What I am 
confused about is that DataTypeUtils.java is checking the value to verify it is 
a Collection<?> but this is obviously returning false and it is falling through 
to throw the exception. This does not only happen on detach but also when 
acessing the List to add a child to it.

java.lang.IllegalArgumentException: A collection of values is required.
    at com.google.appengine.api.datastore.DataTypeUtils.checkSupportedValue(DataTypeUtils.java:157)
    at com.google.appengine.api.datastore.Query$FilterPredicate.<init>(Query.java:847)
    at com.google.appengine.api.datastore.Query$FilterOperator.of(Query.java:77)
    at com.google.appengine.api.datastore.Query.addFilter(Query.java:336)
    at com.google.appengine.datanucleus.scostore.FKListStore.getChildrenByKeys(FKListStore.java:383)
    at com.google.appengine.datanucleus.scostore.FKListStore.listIterator(FKListStore.java:360)
    at com.google.appengine.datanucleus.scostore.FKListStore.listIterator(FKListStore.java:346)
    at com.google.appengine.datanucleus.scostore.FKListStore.iterator(FKListStore.java:339)
    at org.datanucleus.store.types.sco.backed.List.loadFromStore(List.java:304)
    at org.datanucleus.store.types.sco.backed.List.toArray(List.java:641)
    at org.datanucleus.store.fieldmanager.DetachFieldManager.internalFetchObjectField(DetachFieldManager.java:177)
    at org.datanucleus.store.fieldmanager.AbstractFetchDepthFieldManager.fetchObjectField(AbstractFetchDepthFieldManager.java:103)
    at org.datanucleus.state.JDOStateManager.detach(JDOStateManager.java:2742)
    at org.datanucleus.ObjectManagerImpl.performDetachOnCloseWork(ObjectManagerImpl.java:4582)
    at org.datanucleus.ObjectManagerImpl.performDetachOnClose(ObjectManagerImpl.java:4545)
    at org.datanucleus.ObjectManagerImpl.close(ObjectManagerImpl.java:1113)
    at org.datanucleus.api.jpa.JPAEntityManager.close(JPAEntityManager.java:193)
    at com.testing.server.PersistenceFilter.doFilter(PersistenceFilter.java:52)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.appengine.tools.development.HeaderVerificationFilter.doFilter(HeaderVerificationFilter.java:35)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.appengine.api.blobstore.dev.ServeBlobFilter.doFilter(ServeBlobFilter.java:60)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
...

import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.OneToMany;

import com.google.appengine.datanucleus.annotations.Unowned;

@Entity
public class Inventory extends DatastoreObject {

    private String name;

    private String description;

    /**
     * List of all inventory items in this object.
     */
    @Unowned
    @OneToMany(cascade={CascadeType.PERSIST, CascadeType.MERGE})
    private List<InventoryItem> inventoryItems = new ArrayList<InventoryItem>();

    public Inventory() {
    }
}

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class DatastoreObject {

    /**
     * This is only here as a stub.
     * 
     * @param id
     * @return
     */
    public static DatastoreObject findDatastoreObject(Long id) {
        return DaoBase.findByClass(DatastoreObject.class, id);
    }

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Long id;

    private Integer version = 0;

    public Long getId() {
        return id;
    }
}

 @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        EntityManager em = null;
        logger.info("Doing filter");
        try {
            em = entityManagerFactory.createEntityManager();
            ThreadLocalPersistenceManager.setThreadLocakEntityManager(em);

            chain.doFilter(req, res);

            ThreadLocalPersistenceManager.removeThreadLocalEntityManager();
        } catch (Exception e) {
            logger.log(Level.SEVERE, "Throwable caught in persistence filter ", e);
        } finally {
            if (em != null) {
                        // This is the line 52 from the exception stack trace listed above.
                em.close();
            }
        }
    }

Here is my persistnence.xml exert with configuration options.

     <persistence-unit name="transactions-optional">
        <provider>org.datanucleus.api.jpa.PersistenceProviderImpl</provider>

        <properties>
            <property name="datanucleus.NontransactionalRead" value="true"/>
            <property name="datanucleus.NontransactionalWrite" value="true"/>
            <property name="datanucleus.ConnectionURL" value="appengine"/>
            <property name="datanucleus.singletonEMFForName" value="true"/>
            <property name="datanucleus.appengine.relationDefault" value="unowned" />
            <property name="datanucleus.appengine.datastoreEnableXGTransactions" value="true"/>
        </properties>
    </persistence-unit>

I have mirrored my classes to look like the unit tests but am still having this 
issue although I am using TABLE_PER_CLASS strategy for inheritence. 

http://code.google.com/p/datanucleus-appengine/source/browse/trunk/tests/com/goo
gle/appengine/datanucleus/test/jpa/UnownedJPAOneToManyUniListSideA.java?spec=svn
935&r=935

OS: OSX Snow Leopard
GAE: 1.7.1 development server.
Java version: build 1.6.0_33-b03-424-10M3720

Runtime Jars:
appengine-api-1.0-sdk-1.7.1.jar         hibernate-validator-4.3.0.Final-sources.jar
appengine-api-labs.jar              hibernate-validator-4.3.0.Final.jar
appengine-endpoints.jar             jackson-annotations-2.0.5.jar
appengine-jsr107cache-1.7.1.jar         jackson-core-2.0.5.jar
asm-4.0.jar                 jackson-databind-2.0.5.jar
commons-fileupload-1.2.2.jar            jboss-logging-3.1.0.GA.jar
commons-lang3-3.1.jar               jcommon-1.0.16.jar
datanucleus-api-jdo-3.1.0-m3.jar        jdo-api-3.0.1.jar
datanucleus-api-jpa-3.1.0-m3.jar        jsr107cache-1.1.jar
datanucleus-appengine-2.1.0-final.jar       jta-1.1.jar
datanucleus-core-3.1.0-m5.jar           restfb-1.6.9.jar
geronimo-jpa_2.0_spec-1.0.jar           validation-api-1.0.0.GA-sources.jar
gwt-servlet-deps.jar                validation-api-1.0.0.GA.jar
gwt-servlet.jar

Original issue reported on code.google.com by chris.hi...@gmail.com on 27 Aug 2012 at 1:24

GoogleCodeExporter commented 8 years ago
Just wanted to make it more clear that this does not happen when using a Set or 
Collection but only happens when using a List.

Original comment by chris.hi...@gmail.com on 27 Aug 2012 at 1:26

GoogleCodeExporter commented 8 years ago
I built the 2.1.1 snapshot from source and it appears that the null check in 
commit 936 has resolved my problem. 

Thanks

Original comment by chris.hi...@gmail.com on 27 Aug 2012 at 6:08

GoogleCodeExporter commented 8 years ago

Original comment by googleco...@yahoo.co.uk on 27 Aug 2012 at 6:36