0
votes

I am very new to Objectify and I am trying to create endpoints for a simple object. The issue that I am running into is that the endpoint class that Eclipse auto creates has references to JPA. Do I have to manually create my own endpoint class instead of using the "Generate Endpoint Class" in Eclipse? Here are the steps I took to set up my project and the source code:

  1. Created a Web Application Project in Eclipse (app engine project)
  2. Added Objectify-5.0.3.jar and guava-17.0.jar files to web-inf/lib and project's class path
  3. Created a simple class Car.java and added annotations
  4. Registered the entity in servlet (ObjectifyService.register(Car.class);
  5. Right clicked on the Car class and selected Google App Engine (WPT) > Generate Cloud End Point Class
  6. Deployed to App Engine and from API Explorer tried to insert a record and I got this error in logs:

    https://objectify-example-650.appspot.com/_ah/api/carendpoint/v1/car
    Method: carendpoint.insertCar
    Error Code: 400
    Reason: badRequest
    Message: java.lang.IllegalArgumentException: Type ("com.appengine.objectify.Car") is not that of an entity but needs to be for this operation
    

I also see this error/warning in app engine project log:

<pre>
org.datanucleus.metadata.MetaDataManager loadPersistenceUnit: Class com.appengine.objectify.CarEndpoint was specified in persistence-unit transactions-optional but not annotated, so ignoring
</pre>

Here is my source code:

import com.googlecode.objectify.annotation.Entity;
@Entity
public class Car {
    @Id Long id;
    String vin;
    String color;
    private Car() {}
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getVin() {
        return vin;
    }
    public void setVin(String vin) {
        this.vin = vin;
    }
    public String getColor() {
        return color;
    }
    public void setColor(String color) {
        this.color = color;
    }

}

The endpoint class:

@Api(name = "carendpoint", namespace = @ApiNamespace(ownerDomain = "appengine.com",    ownerName = "appengine.com", packagePath = "objectify"))
public class CarEndpoint {

@SuppressWarnings({ "unchecked", "unused" })
@ApiMethod(name = "listCar")
public CollectionResponse<Car> listCar(
        @Nullable @Named("cursor") String cursorString,
        @Nullable @Named("limit") Integer limit) {

    EntityManager mgr = null;
    Cursor cursor = null;
    List<Car> execute = null;

    try {
        mgr = getEntityManager();
        Query query = mgr.createQuery("select from Car as Car");
        if (cursorString != null && cursorString != "") {
            cursor = Cursor.fromWebSafeString(cursorString);
            query.setHint(JPACursorHelper.CURSOR_HINT, cursor);
        }

        if (limit != null) {
            query.setFirstResult(0);
            query.setMaxResults(limit);
        }

        execute = (List<Car>) query.getResultList();
        cursor = JPACursorHelper.getCursor(execute);
        if (cursor != null)
            cursorString = cursor.toWebSafeString();

        for (Car obj : execute)
            ;
    } finally {
        mgr.close();
    }

    return CollectionResponse.<Car> builder().setItems(execute)
            .setNextPageToken(cursorString).build();
}


@ApiMethod(name = "getCar")
public Car getCar(@Named("id") Long id) {
    EntityManager mgr = getEntityManager();
    Car car = null;
    try {
        car = mgr.find(Car.class, id);
    } finally {
        mgr.close();
    }
    return car;
}

@ApiMethod(name = "insertCar")
public Car insertCar(Car car) {
    EntityManager mgr = getEntityManager();
    try {
        if (containsCar(car)) {
            throw new EntityExistsException("Object already exists");
        }
        mgr.persist(car);
    } finally {
        mgr.close();
    }
    return car;
}

@ApiMethod(name = "updateCar")
public Car updateCar(Car car) {
    EntityManager mgr = getEntityManager();
    try {
        if (!containsCar(car)) {
            throw new EntityNotFoundException("Object does not exist");
        }
        mgr.persist(car);
    } finally {
        mgr.close();
    }
    return car;
}

@ApiMethod(name = "removeCar")
public void removeCar(@Named("id") Long id) {
    EntityManager mgr = getEntityManager();
    try {
        Car car = mgr.find(Car.class, id);
        mgr.remove(car);
    } finally {
        mgr.close();
    }
}

private boolean containsCar(Car car) {
    EntityManager mgr = getEntityManager();
    boolean contains = true;
    try {
        Car item = mgr.find(Car.class, car.getId());
        if (item == null) {
            contains = false;
        }
    } finally {
        mgr.close();
    }
    return contains;
}

private static EntityManager getEntityManager() {
    return EMF.get().createEntityManager();
}

}

EFM class created by eclipse when autogenerating the endpoint class:

import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public final class EMF {
    private static final EntityManagerFactory emfInstance = Persistence
            .createEntityManagerFactory("transactions-optional");

    private EMF() {
    }

    public static EntityManagerFactory get() {
        return emfInstance;
    }
}
2

2 Answers

0
votes

The auto-gen cloud endpoint classes, are for JPA/ JDO only, its covered here: Objectify with Endpoints for android Hope that helps

0
votes

Thanks Tim! I ended up writing the endpoint class. As you mentioned eclipse does not create endpoint class for classes annotated for Objectity.

package com.appengine.objectify;

import static com.appengine.objectify.OfyService.ofy;
import com.google.api.server.spi.config.Api;
import com.google.api.server.spi.config.ApiMethod;
import com.google.api.server.spi.config.ApiNamespace;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Named;

@Api(name = "carendpoint", namespace = @ApiNamespace(ownerDomain = "appengine.com", ownerName = "appengine.com", packagePath = "objectify"))
public class CarEndpoint {

    @ApiMethod(name = "listCar")
    public List<Car> listCar() {
        List<Car> result = new ArrayList<Car>();
        result = ofy().load().type(Car.class).list();
        return result;
    }

    @ApiMethod(name = "getCar")
    public Car getCar(@Named Long id) {
        Car Car = ofy().load().type(Car.class).id(id).now();
        return Car;
    }

    @ApiMethod(name = "insertCar")
    public Car insertCar(Car Car) {
        ofy().save().entity(Car).now();
        return Car;
    }

    @ApiMethod(name = "removeCar")
    public void removeCar(@Named Long id) {
        ofy().delete().type(Car.class).id(id).now();
    }


}