Java Content eines PUT (REST)

FaKer

Cadet 4th Year
Registriert
Jan. 2004
Beiträge
100
Hallo mal wieder,

ich habe via Netbeans einen REST-Service, ausgehend von einer Datenbank, erstellen lassen.
Die ganzen GET,PUT,POST,DELETE funtkionieren eigentlich.

Ich habe nun ein Problem bzgl. dem Updaten eines Datensatzes via PUT.
Die Tabelle rooms besteht aus den Spalten id, name, nameDetail, tempIs. id ist dabei der PK.

Folglich wurde daraus ein Entity erzeugt mit eben diesen Variablen.
Möchte ich nun ein PUT auf eine Rooms-Ressource ausführen, funktioniert das blos, wenn ich alle Parameter mitgebe.
Über die Test-Seite die von Netbeans erstellt wurde, wären das die Parameter um den Datensatz zu aktualisieren:
(via JSON)
Code:
id: 1
Content: {"id":"1","name":"Küche","nameDetail":"detail_kitchen","tempIs":"20"}

Das funktioniert.

Die REST-Schnittstelle benötige ich um von einer Android App Zugriff auf die Datenbank zu bekommen.
Ich möchte nun lediglich einen von den Parametern aktualisieren. Ich habe das dann so versucht:

Code:
id: 1
{"tempIs":"20"}

Als Rückmeldung bekomm ich den Status Code 500, Internal Server Error.
Die Fehlermeldung ausm Log vom Server:

Code:
13.03.2011 15:22:05 org.apache.catalina.core.StandardWrapperValve invoke
SCHWERWIEGEND: Servlet.service() for servlet ServletAdaptor threw exception
java.lang.RuntimeException: javax.persistence.RollbackException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.0.2.v20100323-r6872): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Column 'id' cannot be null
Error Code: 1048
Call: INSERT INTO rooms (id, name, temp_is, name_detail) VALUES (?, ?, ?, ?)
        bind => [null, null, 20, null]
Query: InsertObjectQuery(entities.Rooms[id=null])
        at service.PersistenceService.commitTx(PersistenceService.java:89)
        at service.RoomsResource.put(RoomsResource.java:78)
        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 com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$VoidOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:132)
        at com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:67)
        at com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:259)
        at com.sun.jersey.server.impl.uri.rules.SubLocatorRule.accept(SubLocatorRule.java:118)
        at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:133)
        at com.sun.jersey.server.impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:83)
        at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:133)
        at com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:71)
        at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:990)
        at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:941)
        at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:932)
        at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:384)
        at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:451)
        at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:632)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:393)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:852)
        at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
        at java.lang.Thread.run(Thread.java:662)
Caused by: javax.persistence.RollbackException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.0.2.v20100323-r6872): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Column 'id' cannot be null
Error Code: 1048
Call: INSERT INTO rooms (id, name, temp_is, name_detail) VALUES (?, ?, ?, ?)
        bind => [null, null, 20, null]
Query: InsertObjectQuery(entities.Rooms[id=null])
        at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commitInternal(EntityTransactionImpl.java:102)
        at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commit(EntityTransactionImpl.java:63)
        at service.PersistenceService.commitTx(PersistenceService.java:87)
        ... 35 more
Caused by: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.0.2.v20100323-r6872): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Column 'id' cannot be null
Error Code: 1048
Call: INSERT INTO rooms (id, name, temp_is, name_detail) VALUES (?, ?, ?, ?)
        bind => [null, null, 20, null]
Query: InsertObjectQuery(entities.Rooms[id=null])
        at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:324)
        at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:801)
        at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeNoSelect(DatabaseAccessor.java:867)
        at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:587)
        at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeCall(DatabaseAccessor.java:530)
        at org.eclipse.persistence.internal.sessions.AbstractSession.executeCall(AbstractSession.java:914)
        at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:206)
        at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:192)
        at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.insertObject(DatasourceCallQueryMechanism.java:335)
        at org.eclipse.persistence.internal.queries.StatementQueryMechanism.insertObject(StatementQueryMechanism.java:162)
        at org.eclipse.persistence.internal.queries.StatementQueryMechanism.insertObject(StatementQueryMechanism.java:177)
        at org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.insertObjectForWrite(DatabaseQueryMechanism.java:462)
        at org.eclipse.persistence.queries.InsertObjectQuery.executeCommit(InsertObjectQuery.java:80)
        at org.eclipse.persistence.queries.InsertObjectQuery.executeCommitWithChangeSet(InsertObjectQuery.java:90)
        at org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.executeWriteWithChangeSet(DatabaseQueryMechanism.java:287)
        at org.eclipse.persistence.queries.WriteObjectQuery.executeDatabaseQuery(WriteObjectQuery.java:58)
        at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:675)
        at org.eclipse.persistence.queries.DatabaseQuery.executeInUnitOfWork(DatabaseQuery.java:589)
        at org.eclipse.persistence.queries.ObjectLevelModifyQuery.executeInUnitOfWorkObjectLevelModifyQuery(ObjectLevelModifyQuery.java:109)
        at org.eclipse.persistence.queries.ObjectLevelModifyQuery.executeInUnitOfWork(ObjectLevelModifyQuery.java:86)
        at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2898)
        at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1225)
        at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1207)
        at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1167)
        at org.eclipse.persistence.internal.sessions.CommitManager.commitNewObjectsForClassWithChangeSet(CommitManager.java:197)
        at org.eclipse.persistence.internal.sessions.CommitManager.commitAllObjectsWithChangeSet(CommitManager.java:103)
        at org.eclipse.persistence.internal.sessions.AbstractSession.writeAllObjectsWithChangeSet(AbstractSession.java:3260)
        at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabase(UnitOfWorkImpl.java:1413)
        at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.commitToDatabase(RepeatableWriteUnitOfWork.java:547)
        at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithChangeSet(UnitOfWorkImpl.java:1518)
        at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.commitRootUnitOfWork(RepeatableWriteUnitOfWork.java:200)
        at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitAndResume(UnitOfWorkImpl.java:1139)
        at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commitInternal(EntityTransactionImpl.java:84)
        ... 37 more
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Column 'id' cannot be null
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
        at com.mysql.jdbc.Util.handleNewInstance(Util.java:406)
        at com.mysql.jdbc.Util.getInstance(Util.java:381)
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1015)
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956)
        at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3491)
        at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3423)
        at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1936)
        at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2060)
        at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2542)
        at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1734)
        at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2019)
        at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1937)
        at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1922)
        at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:792)
        ... 68 more

hier mal die Code-Schnippsel wie sie meiner meinung nach aufgerufen werden:

RoomssResource.java
Code:
    /**
     * Returns a dynamic instance of RoomsResource used for entity navigation.
     *
     * @return an instance of RoomsResource
     */
    @Path("{id}/")
    public RoomsResource getRoomsResource(@PathParam("id") Integer id) {
        RoomsResource roomsResource = resourceContext.getResource(RoomsResource.class);
        roomsResource.setId(id);
        return roomsResource;
    }

RoomsResource.java
Code:
/**
     * Put method for updating an instance of Rooms identified by id using XML as the input format.
     *
     * @param id identifier for the entity
     * @param data an RoomsConverter entity that is deserialized from a XML stream
     */
    @PUT
    @Consumes({"application/xml", "application/json"})
    public void put(RoomsConverter data) {
        PersistenceService persistenceSvc = PersistenceService.getInstance();
        try {
            persistenceSvc.beginTx();
            EntityManager em = persistenceSvc.getEntityManager();
            updateEntity(getEntity(), data.resolveEntity(em));
            persistenceSvc.commitTx();
        } finally {
            persistenceSvc.close();
        }
    }

/**
     * Returns an instance of Rooms identified by id.
     *
     * @param id identifier for the entity
     * @return an instance of Rooms
     */
    protected Rooms getEntity() {
        EntityManager em = PersistenceService.getInstance().getEntityManager();
        try {
            return (Rooms) em.createQuery("SELECT e FROM Rooms e where e.id = :id").setParameter("id", id).getSingleResult();
        } catch (NoResultException ex) {
            throw new WebApplicationException(new Throwable("Resource for " + uriInfo.getAbsolutePath() + " does not exist."), 404);
        }
    }

}

    /**
     * Updates entity using data from newEntity.
     *
     * @param entity the entity to update
     * @param newEntity the entity containing the new data
     * @return the updated entity
     */
    private Rooms updateEntity(Rooms entity, Rooms newEntity) {
        EntityManager em = PersistenceService.getInstance().getEntityManager();
        entity = em.merge(newEntity);
        return entity;
    }

RoomsConverter.java
Code:
/**
     * Returns the resolved Rooms entity.
     *
     * @return an resolved entity
     */
    public Rooms resolveEntity(EntityManager em) {
        return entity;
    }


Der Fehler entsteht hier:
Code:
private Rooms updateEntity(Rooms entity, Rooms newEntity) {
        EntityManager em = PersistenceService.getInstance().getEntityManager();
        entity = em.merge(newEntity);
        return entity;
    }

entitiy ist das Objekt, das von getEntitiy() zurückgegeben wurde. Also der "Datensatz" den ich updaten möchte. newEntity entsteht aus den Daten, die ich per PUT übergebe. da ich ja blos den parameter tempIs übergeben habe, wurden die anderen parameter mit NULL initisalisiert.
Deswegen wohl die Fehlermeldung: Column cannot be null.

Was kann ich nun machen, dass ich trotzdem blos einen parameter übermittel? viele werte in der db ändern sich, sodass ich nie alle werte in meiner app synchron halten kann. somit ist es mir unmöglich wenn ich blos einen parameter updaten muss, alle anderen auch mit zu schicken.

bin dankbar für jeden vorschlag :)
vg
 
Ich finde es merkwürdig, dass in der Fehlermeldung von "INSERT INTO" die Rede ist, und nicht von "UPDATE". Denn beim Einfügen müssen ja alle Parameter gesetzt sein.
 
Werd das gleich mal im debugger durchschauen wieso das so ist...
Ergänzung ()

Okay, wieder gefixed...

ich hab in der updateEntity()-Funktion geprüft, welche paramter=null und diese dann mit den ursprünglichen werten belegt:

Code:
/**
     * Updates entity using data from newEntity.
     *
     * @param entity the entity to update
     * @param newEntity the entity containing the new data
     * @return the updated entity
     */
    private Rooms updateEntity(Rooms entity, Rooms newEntity) {
        EntityManager em = PersistenceService.getInstance().getEntityManager();
        if(newEntity.getId() == null) newEntity.setId(entity.getId());
        if(newEntity.getName() == null) newEntity.setName(entity.getName());
        if(newEntity.getNameDetail() == null) newEntity.setNameDetail(entity.getNameDetail());
        if(newEntity.getTempIs() == null) newEntity.setTempIs(entity.getTempIs());
        entity = em.merge(newEntity);
        return entity;
    }

aber warum da nun eben in der meldung insert stand und nicht update weiß ich nicht? evtl weil die parameter nicht übereinstimmten und der dann versucht hat n insert durchzuführen? not sure...
 
Zuletzt bearbeitet:
Hm gut möglich, dass er automatisch erkennt, ob ein INSERT oder UPDATE ausgeführt werden sollte. So wie du es jetzt machst, sieht es eigentlich richtig aus, wenn auch ein wenig umständlich (aber keine Ahnung ob man das kompakter machen kann).
 
Zurück
Oben