如何构建(通用)端点控制器类(层次结构)

时间:2014-12-02 22:38:29

标签: scala google-app-engine generics google-cloud-endpoints objectify

我想创建几个端点控制器类(使用Objectify),并且因为它们共享许多公共代码,所以使用一些通用基类。 我想做这样的事情:

@Api(
  backendRoot = "http://localhost:8888/_ah/spi",
  root = "http://localhost:8888/_ah/api",
  version = "v1"
)
abstract class BaseController[T <: Entity[T]] {

  protected def getApiClass() : Class[T]

  @ApiMethod(
    name = "read",
    path = "read",
    httpMethod = HttpMethod.GET
  )
  def read() : JList[T] =   {
    OfyS.ofy().load().`type`(getApiClass()).list().asInstanceOf[JList[T]]
  }  

  def create(entity : T) : T =  {
  …
  }
…
}

@Api(
  name = "misc"
)
class MiscController extends BaseController[Misc] {
    override protected def getApiClass() = classOf[Misc]
}

作为几个实现之一。这样,我基本上只需要在每个实现中替换类型和API名称(这是基本的想法)。

唉,Endpoints尝试将getApiClass()公开给API,我得到了

java.lang.IllegalArgumentException: Parameterized type java.lang.Class<Misc> not supported

(afaik,我不能在这里省略类型参数化。)

虽然该方法受到保护且文档声明只公开公共方法,但仍会发生这种情况。这可能是因为Scala的'protected'味道(我根本就不知道)。如果它是私有的(如果我没有使用类层次结构,它基本上有效),我无法覆盖它。

您是否有任何关于如何使基本想法发挥作用的线索?

1 个答案:

答案 0 :(得分:0)

好问题!以下是我如何解决这个问题...

我的端点中的每一个都是这样的:

警告:这不是生产就绪代码! (特别是,请注意我没有使用光标。由于我面临的问题不同,我无法做到。)

public class MyEndpoint {
@ApiMethod(
    name = "get",
    path = "bean/{id}",
    httpMethod = ApiMethod.HttpMethod.GET)
public Bean get(@Named("id") Long id) throws NotFoundException {
    return new MyService().get(id);
    }
    ...
}

现在,让我们看一下 MyService 类:

public class MyService extends AbstractService<Long, Bean> {
    static {
        ObjectifyService.register(Bean.class);
    }
    public MyService() {
        super(Long.class, Bean.class);
    }
}

最后, AbstractService

    public class AbstractService<D, T> {
        protected static final Logger logger = Logger.getLogger(AbstractService.class.getName());
        private final Class<?> idClazz;
        private final Class<? extends T> clazz;
        public AbstractService(Class<?> idClazz, Class<? extends T> clazz) {
            this.idClazz = idClazz;
            this.clazz = clazz;
        }

public T get(D id) throws NotFoundException {
            logger.info("Getting " + clazz.getName() + " with ID: " + id);
            T obj = null;
            if (idClazz == Long.class) {
                Long parsedId = (Long) id;
                obj = ofy().load().type(clazz).id(parsedId).now();
            } else if (idClazz == String.class) {
                String parsedId = (String) id;
                obj = ofy().load().type(clazz).id(parsedId).now();
            }
            if (obj == null) {
                throw new NotFoundException("Could not find " + getClass().getName() + " with ID: " + id);
            }
            return obj;
        }

        public T insert(T obj) {
            ofy().save().entity(obj).now();
            logger.info("Created " + clazz.getName() + ".");
            return ofy().load().entity(obj).now();
        }

        public T update(D id, T obj) throws NotFoundException {
            checkExists(id);
            ofy().save().entity(obj).now();
            logger.info("Updated " + clazz.getName() + ": " + obj);
            return ofy().load().entity(obj).now();
        }

        public void remove(D id) throws NotFoundException {
            checkExists(id);
            T obj = null;
            if (idClazz == Long.class) {
                Long parsedId = (Long) id;
                ofy().delete().type(clazz).id(parsedId).now();
            } else if (idClazz == String.class) {
                String parsedId = (String) id;
                ofy().delete().type(clazz).id(parsedId).now();
            }
            logger.info("Deleted " + getClass().getName() + " with ID: " + id);
        }

        public CollectionResponse<T> list() {
            //        limit = limit == null ? DEFAULT_LIST_LIMIT : limit;
            logger.info("Listing " + clazz.getName() + "s");
            Query<? extends T> query = ofy().load().type(clazz);
            QueryResultIterator<? extends T> queryIterator = query.iterator();
            List<T> objList = new ArrayList<T>();
            while (queryIterator.hasNext()) {
                objList.add(queryIterator.next());
            }
            return CollectionResponse.<T>builder().setItems(objList).build();
        }

        public CollectionResponse<T> list(int limit, int startAt) {
            logger.info("Listing " + clazz.getName() + "s");
            Query<? extends T> query = ofy().load().type(clazz).offset(startAt).limit(limit);
            QueryResultIterator<? extends T> queryIterator = query.iterator();
            List<T> objList = new ArrayList<T>();
            while (queryIterator.hasNext()) {
                objList.add(queryIterator.next());
            }
            return CollectionResponse.<T>builder().setItems(objList).build();
        }

        private void checkExists(D id) throws NotFoundException {
            try {
                if (idClazz == Long.class) {
                    Long parsedId = (Long) id;
                    ofy().load().type(clazz).id(parsedId).safe();
                } else if (idClazz == String.class) {
                    String parsedId = (String) id;
                    ofy().load().type(clazz).id(parsedId).safe();
                }
            } catch (com.googlecode.objectify.NotFoundException e) {
                throw new NotFoundException("Could not find " + getClass().getName() + " with ID: " + id);
            }
        }
    }