Skip to content

Instantly share code, notes, and snippets.

@kdmukai
Created July 24, 2011 08:45
Show Gist options
  • Save kdmukai/1102416 to your computer and use it in GitHub Desktop.
Save kdmukai/1102416 to your computer and use it in GitHub Desktop.
Final versions of ObjectifyGenericDAO with interfaces
package com.essaytagger.server.impl;
import com.essaytagger.model.Comment;
import com.essaytagger.model.Essay;
import com.essaytagger.server.IEssayManagerExtensions;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.googlecode.objectify.Key;
/**
* Implementation class for any Essay-specific methods that aren't already handled by ObjectifyGenericDAO<T>.
*/
public class EssayManagerExtensionsImpl extends ObjectifyGenericDAO<Essay> implements IEssayManagerExtensions {
public EssayManagerExtensionsImpl() {
// Generic type needs to be explicitly passed to the ObjectifyGenericDAO<T> constructor
super(Essay.class);
}
/**************************************************************
* Overrides of the GenericDAO implementations
*************************************************************/
@Override
public void delete(Essay entity) {
// First do something special and specific for Essay entities
// ...
// Now we can delete the entity from the datastore
super.delete(entity);
}
// Also have to override this version to control all delete() behavior
@Override
public void deleteKey(Key<Essay> entityKey) {
try {
Essay essay = this.get(entityKey);
delete(essay);
} catch (EntityNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/*************************************************************************************************
* Implementation of new methods from the Extension interface
************************************************************************************************/
public void addCommentToEssay(Essay essay, Comment comment) {
// Implement the business logic specific to this unique method
// ...
}
}
package com.essaytagger.server;
import com.essaytagger.model.BasicUser;
import com.essaytagger.model.Essay;
import com.essaytagger.server.impl.EssayManagerExtensionsImpl;
import com.essaytagger.server.impl.ObjectifyGenericDAO;
import com.googlecode.objectify.ObjectifyService;
public class EssayTaggerManagerFactory {
// Declare entity-specific versions of each Generic interface
public interface IBasicUserManager extends IGenericDAO<BasicUser> {}
public interface IEssayManager extends IEssayManagerExtensions {}
// The use those interfaces as we declare entity-specific DAOs
private static class BasicUserManager extends ObjectifyGenericDAO<BasicUser> implements IBasicUserManager {}
private static class EssayManager extends EssayManagerExtensionsImpl implements IEssayManager {}
static {
ObjectifyService.register(BasicUser.class);
ObjectifyService.register(Essay.class);
}
// Static-only usage pattern
protected EssayTaggerManagerFactory() {}
public static IEssayManager getEssayManager() {
return new EssayManager();
}
public static IBasicUserManager getBasicUserManager() {
return new BasicUserManager();
}
}
package com.essaytagger.server;
import com.essaytagger.model.Comment;
import com.essaytagger.model.Essay;
/**
* Declare additional Essay-specific methods that aren't covered in the IGenericDAO<T> interface.
*/
public interface IEssayManagerExtensions extends IGenericDAO<Essay> {
public void addCommentToEssay(Essay essay, Comment comment);
}
package com.essaytagger.server;
import java.util.List;
import java.util.Map;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.googlecode.objectify.Key;
public interface IGenericDAO<T> {
public Key<T> put(T entity);
public Map<Key<T>, T> putAll(Iterable<T> entities);
public void delete(T entity);
public void deleteKey(Key<T> entityKey);
public void deleteAll(Iterable<T> entities);
public void deleteKeys(Iterable<Key<T>> keys);
public T get(Long id) throws EntityNotFoundException;
public T get(Key<T> key) throws EntityNotFoundException;
/*
* Convenience method to generate a typed Key<T> for a given id
*/
public Key<T> getKey(Long id);
/*
* Get ALL entities of type <T> in the datastore. Potentially very inefficient!!
* Make sure you have a good reason to use this!!
*/
public List<T> listAll();
/**
* Convenience method to get all objects matching a single property
*
* @param propName
* @param propValue
* @return T matching Object
*/
public T getByProperty(String propName, Object propValue);
public List<T> listByProperty(String propName, Object propValue);
public List<Key<T>> listKeysByProperty(String propName, Object propValue);
public T getByExample(T exampleObj);
public List<T> listByExample(T exampleObj);
}
package com.essaytagger.server.impl;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.persistence.Embedded;
import javax.persistence.Transient;
import com.essaytagger.server.IGenericDAO;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.Query;
import com.googlecode.objectify.util.DAOBase;
public abstract class ObjectifyGenericDAO<T> extends DAOBase implements IGenericDAO<T> {
static final int BAD_MODIFIERS = Modifier.FINAL | Modifier.STATIC | Modifier.TRANSIENT;
protected Class<T> clazz;
@SuppressWarnings("unchecked")
public ObjectifyGenericDAO() {
clazz = ((Class<T>)((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
}
/**
* We've got to get the associated domain class somehow
*
* @param clazz
*/
protected ObjectifyGenericDAO(Class<T> clazz)
{
this.clazz = clazz;
}
public Key<T> put(T entity)
{
return ofy().put(entity);
}
public Map<Key<T>, T> putAll(Iterable<T> entities)
{
return ofy().put(entities);
}
public void delete(T entity)
{
ofy().delete(entity);
}
public void deleteKey(Key<T> entityKey)
{
ofy().delete(entityKey);
}
public void deleteAll(Iterable<T> entities)
{
ofy().delete(entities);
}
public void deleteKeys(Iterable<Key<T>> keys)
{
ofy().delete(keys);
}
public T get(Long id) throws EntityNotFoundException
{
return ofy().get(this.clazz, id);
}
public T get(Key<T> key) throws EntityNotFoundException
{
return ofy().get(key);
}
/*
* Convenience method to generate a typed Key<T> for a given id
*/
public Key<T> getKey(Long id) {
return new Key<T>(clazz, id);
}
/*
* Get ALL entities of type <T> in the datastore. DANGEROUS!! INEFFICIENT!!
* Only doing this for dev/debugging purposes.
*/
public List<T> listAll()
{
Query<T> q = ofy().query(clazz);
return asList(q.fetch());
}
/**
* Convenience method to get all objects matching a single property
*
* @param propName
* @param propValue
* @return T matching Object
*/
public T getByProperty(String propName, Object propValue)
{
Query<T> q = ofy().query(clazz);
q.filter(propName, propValue);
return q.get();
}
public List<T> listByProperty(String propName, Object propValue)
{
Query<T> q = ofy().query(clazz);
q.filter(propName, propValue);
return asList(q.fetch());
}
public List<Key<T>> listKeysByProperty(String propName, Object propValue)
{
Query<T> q = ofy().query(clazz);
q.filter(propName, propValue);
return asKeyList(q.fetchKeys());
}
public T getByExample(T exampleObj)
{
Query<T> queryByExample = buildQueryByExample(exampleObj);
Iterable<T> iterableResults = queryByExample.fetch();
Iterator<T> i = iterableResults.iterator();
T obj = i.next();
if (i.hasNext())
throw new RuntimeException("Too many results");
return obj;
}
public List<T> listByExample(T exampleObj)
{
Query<T> queryByExample = buildQueryByExample(exampleObj);
return asList(queryByExample.fetch());
}
private List<T> asList(Iterable<T> iterable)
{
ArrayList<T> list = new ArrayList<T>();
for (T t : iterable)
{
list.add(t);
}
return list;
}
private List<Key<T>> asKeyList(Iterable<Key<T>> iterableKeys)
{
ArrayList<Key<T>> keys = new ArrayList<Key<T>>();
for (Key<T> key : iterableKeys)
{
keys.add(key);
}
return keys;
}
private Query<T> buildQueryByExample(T exampleObj)
{
Query<T> q = ofy().query(clazz);
// Add all non-null properties to query filter
for (Field field : clazz.getDeclaredFields())
{
// Ignore transient, embedded, array, and collection properties
if (field.isAnnotationPresent(Transient.class)
|| (field.isAnnotationPresent(Embedded.class))
|| (field.getType().isArray())
|| (Collection.class.isAssignableFrom(field.getType()))
|| ((field.getModifiers() & BAD_MODIFIERS) != 0))
continue;
field.setAccessible(true);
Object value;
try
{
value = field.get(exampleObj);
}
catch (IllegalArgumentException e)
{
throw new RuntimeException(e);
}
catch (IllegalAccessException e)
{
throw new RuntimeException(e);
}
if (value != null)
{
q.filter(field.getName(), value);
}
}
return q;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment