Sunday, August 26, 2012

AppEngine Datastore REST and Key in Entities

To begin with I have worked with AppEngine Keys but found out during testing that this won't work. The key can't be converted and returned with the jax-rs Response class as in general only Java types (int, string....) can be returned.

Example:
@Path("/card")
public class CardResource {
    CardDAO dao = new CardDAO();

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Response create(Card card) {
        Card c = dao.create(card);
        if(c.equals(null)) {
            return Response.status(Status.BAD_REQUEST)
                    .type(MediaType.APPLICATION_JSON)
                    .entity("Create failed!")
                    .build();
        }
      
        return Response.status(Status.OK)
                .entity(c)
                .type(MediaType.APPLICATION_JSON)
                .build();
    }
}

The Response class will return the entity as a JSON object in this case. But the key is returned as "null" value when using the AppEngine Key class.

There are two solutions to this problem:

Solution 1
Work with Long instead of Key. This is fine if you want to use a number as key and don't have to mix it with data that could have an identical key.

Here a sample entity:
import java.util.Date;

import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
@PersistenceCapable(detachable="true")
public class Card {
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Long key;
    
    @Persistent
    private String name;
    
    @Persistent
    private Date creationDate;    
    
    @Persistent
    private Date modificationDate;
    
    public Card() {
        this.setName(null);
        this.setCreationDate(null);
        this.setModificationDate(null);
    }
    
    public Card(String name)
        this.setName(name);
        this.setCreationDate(new Date());
        this.setModificationDate(new Date());
    }

    public Long getKey() {
        return key;
    }

    public void setKey(Long key) {
        this.key = key;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Date getCreationDate() {
        return creationDate;
    }

    public void setCreationDate(Date creationDate) {
        this.creationDate = creationDate;
    }

    public Date getModificationDate() {
        return modificationDate;
    }

    public void setModificationDate(Date modificationDate) {
        this.modificationDate = modificationDate;
    }
}

Solution2
Work with Encoded String as Key. This solution is the prefered one as the generated string is a random string that does not conflict with any other id of a different data set if you have to mix the data together with other data created elsewhere.

Here a sample entity:
import java.util.Date;

import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
@PersistenceCapable(detachable="true")
public class Card {
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    @Extenstion(vendorName="datanucleus",  key="gae.encoded-pk", value="true")
    private String key;
    
    @Persistent
    private String name;
    
    @Persistent
    private Date creationDate;    
    
    @Persistent
    private Date modificationDate;
    
    public Card() {
        this.setName(null);
        this.setCreationDate(null);
        this.setModificationDate(null);
    }
    
    public Card(String name)
        this.setName(name);
        this.setCreationDate(new Date());
        this.setModificationDate(new Date());
    }

    public Long getKey() {
        return key;
    }

    public void setKey(Long key) {
        this.key = key;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Date getCreationDate() {
        return creationDate;
    }

    public void setCreationDate(Date creationDate) {
        this.creationDate = creationDate;
    }

    public Date getModificationDate() {
        return modificationDate;
    }

    public void setModificationDate(Date modificationDate) {
        this.modificationDate = modificationDate;
    }
}

No comments:

Post a Comment