Generate Map<String,String> from POJO - java

I have a POJO, and a (currently not-yet-built) class that will return Lists of it. I'd like to automatically generate the code necessary for the POJO to be accessed as a Map. Is this a good idea, is it possible to do automatically, and do I need to do this manually for every POJO I want to treat this way?
Thanks,
Andy

You can use Commons BeanUtils BeanMap for this.
Map map = new BeanMap(someBean);
Update: since that's not an option due to some apparent library dependency problems in Android, here's a basic kickoff example how you could do it with little help of Reflection API:
public static Map<String, Object> mapProperties(Object bean) throws Exception {
Map<String, Object> properties = new HashMap<>();
for (Method method : bean.getClass().getDeclaredMethods()) {
if (Modifier.isPublic(method.getModifiers())
&& method.getParameterTypes().length == 0
&& method.getReturnType() != void.class
&& method.getName().matches("^(get|is).+")
) {
String name = method.getName().replaceAll("^(get|is)", "");
name = Character.toLowerCase(name.charAt(0)) + (name.length() > 1 ? name.substring(1) : "");
Object value = method.invoke(bean);
properties.put(name, value);
}
}
return properties;
}
If java.beans API were available, then you could just do:
public static Map<String, Object> mapProperties(Object bean) throws Exception {
Map<String, Object> properties = new HashMap<>();
for (PropertyDescriptor property : Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors()) {
String name = property.getName();
Object value = property.getReadMethod().invoke(bean);
properties.put(name, value);
}
return properties;
}

Here's my own implementation without any dependencies. Rather than make a copy of the object's state, it implements a live Map over the pojo. Android doesn't support java.beans, but you can use openbeans instead.
import java.beans.*; // Or, import com.googlecode.openbeans.*
import java.util.*;
public class BeanMap extends AbstractMap<String, Object> {
private static final Object[] NO_ARGS = new Object[] {};
private HashMap<String, PropertyDescriptor> properties;
private Object bean;
public BeanMap(Object bean) throws IntrospectionException {
this.bean = bean;
properties = new HashMap<String, PropertyDescriptor>();
BeanInfo info = Introspector.getBeanInfo(bean.getClass());
for(PropertyDescriptor property : info.getPropertyDescriptors()) {
properties.put(property.getName(), property);
}
}
#Override public Object get(Object key) {
PropertyDescriptor property = properties.get(key);
if(property == null)
return null;
try {
return property.getReadMethod().invoke(bean, NO_ARGS);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
#Override public Object put(String key, Object value) {
PropertyDescriptor property = properties.get(key);
try {
return property.getWriteMethod().invoke(bean, new Object[] {value});
} catch (Exception e) {
throw new RuntimeException(e);
}
}
#Override public Set<Map.Entry<String, Object>> entrySet() {
HashSet<Map.Entry<String, Object>> result = new HashSet<Map.Entry<String, Object>>(properties.size() * 2);
for(PropertyDescriptor property : properties.values()) {
String key = property.getName();
Object value;
try {
value = property.getReadMethod().invoke(bean, NO_ARGS);
} catch (Exception e) {
throw new RuntimeException(e);
}
result.add(new PropertyEntry(key, value));
}
return Collections.unmodifiableSet(result);
}
#Override public int size() { return properties.size(); }
#Override public boolean containsKey(Object key) {
return properties.containsKey(key);
}
class PropertyEntry extends AbstractMap.SimpleEntry<String, Object> {
PropertyEntry(String key, Object value) {
super(key, value);
}
#Override public Object setValue(Object value) {
super.setValue(value);
return BeanMap.this.put(getKey(), value);
}
}
}

Related

Hazelcast remove from iQueue skipping some elements

I have hazelcast client that is putting generic message class into a iQueue and hazelcast member consume this generic message via Listener do the logic and remove the object from the queue. But it is not removing all the objects. On mancenter i can see that there are still items into the queue (not all for example from 100 objects in queue it is removing around 80 from them) and i don`t know why it is not removing some of the objects.
Currently in mancenter it is showing 12 items into the queue (from arround 100 requests) but it shouldn't have any.Still the code is working and returning results. The only problem is that i can see in mancenter that this items are getting more and more into the queue until i stop the hazelcast server.
My generic message class:
public class GenericMessage<T> implements Message<T>, Serializable {
private static final long serialVersionUID = -1927585972068115172L;
private final T payload;
private MessageHeaders headers;
public GenericMessage(T payload) {
Assert.notNull(payload, "payload must not be null");
HashMap<Object, Object> headers = new HashMap<>();
this.headers = new MessageHeaders(headers);
this.payload = payload;
}
#Override
public MessageHeaders getHeaders() {
return this.headers;
}
#Override
public T getPayload() {
return this.payload;
}
#Override
public String toString() {
return "[Payload=" + this.payload + "][Headers=" + this.headers + "]";
}
#Override
public int hashCode() {
return this.headers.hashCode() * 23 + ObjectUtils.nullSafeHashCode(this.payload);
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj != null && obj instanceof GenericMessage<?>) {
GenericMessage<?> other = (GenericMessage<?>) obj;
if (this.headers.getKey() != null && other.headers.getKey() != null) {
return this.headers.getKey().equals(other.headers.getKey());
} else {
return false;
}
}
return false;
}
}
MessageHeaders class:
public class MessageHeaders implements Map<Object, Object>, Serializable {
private static final long serialVersionUID = 4469807275189880042L;
protected Map<Object, Object> headers;
public static final String KEY = "key";
public MessageHeaders(Map<Object, Object> headers) {
this.headers = (headers != null) ? headers : new HashMap<>();
}
#SuppressWarnings("unchecked")
public <T> T get(Object key, Class<T> type) {
Object value = this.headers.get(key);
if (value == null) {
return null;
}
if (!type.isAssignableFrom(value.getClass())) {
throw new IllegalArgumentException("Incorrect type specified for header '"
+ key
+ "'. Expected ["
+ type
+ "] but actual type is ["
+ value.getClass()
+ "]");
}
return (T) value;
}
#Override
public int hashCode() {
return this.headers.hashCode();
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj != null && obj instanceof MessageHeaders) {
MessageHeaders other = (MessageHeaders) obj;
return this.headers.equals(other.headers);
}
return false;
}
#Override
public boolean containsKey(Object key) {
return this.headers.containsKey(key);
}
#Override
public boolean containsValue(Object value) {
return this.headers.containsValue(value);
}
#Override
public Set<Map.Entry<Object, Object>> entrySet() {
return Collections.unmodifiableSet(this.headers.entrySet());
}
#Override
public Object get(Object key) {
return this.headers.get(key);
}
#Override
public boolean isEmpty() {
return this.headers.isEmpty();
}
#Override
public Set<Object> keySet() {
return Collections.unmodifiableSet(this.headers.keySet());
}
#Override
public int size() {
return this.headers.size();
}
#Override
public Collection<Object> values() {
return Collections.unmodifiableCollection(this.headers.values());
}
#Override
public Object put(Object key, Object value) {
throw new UnsupportedOperationException("MessageHeaders is immutable.");
}
#Override
public void putAll(Map<? extends Object, ? extends Object> t) {
throw new UnsupportedOperationException("MessageHeaders is immutable.");
}
#Override
public Object remove(Object key) {
throw new UnsupportedOperationException("MessageHeaders is immutable.");
}
#Override
public void clear() {
throw new UnsupportedOperationException("MessageHeaders is immutable.");
}
private void writeObject(ObjectOutputStream out) throws IOException {
List<String> keysToRemove = new ArrayList<>();
for (Map.Entry<Object, Object> entry : this.headers.entrySet()) {
if (!(entry.getValue() instanceof Serializable)) {
keysToRemove.add(String.valueOf(entry.getKey()));
}
}
for (String key : keysToRemove) {
// if (logger.isInfoEnabled()) {
// logger.info("removing non-serializable header: " +
// key);
// }
this.headers.remove(key);
}
out.defaultWriteObject();
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
}
public String getKey() {
return this.get(KEY, String.class);
}
public void setKey(String key) {
this.headers.put(KEY, key);
}
}
Putting into queue implementation:
User user = new User();
GenericMessage<User> message = new GenericMessage<User>(user);
String key="123";
message.getHeaders().setKey(key);
IQueue<Object> queue = hazelcastInstance.getQueue("user_queue");
queue.add(message);
Hazelcast listener configuration:
IQueue<Object> userQueue = hazelcastInstance.getQueue("user_queue");
UserListener userListener = context.getBean(UserListener.class);
userQueue.addItemListener(userListener, true);
Listener:
public class UserListener implements ItemListener<Object> {
#Autowired
private UserService service;
#Override
public void itemAdded(ItemEvent<Object> arg0) {
service.process(arg0);
}
}
Service:
public class UserService {
#Async("userTaskExecutor")
public void process(ItemEvent<Object> item) {
GenericMessage<User> message = (GenericMessage<User>) item.getItem();
hazelcastInstance.getQueue("user_queue").remove(message);
}
With a lot of testing and debugging i found the problem.
It turns out that the documentation of the remove(object) method is misleading. In the documentation is says that this method rely on .equals() class method but it turns out that hazelcast compares the serialized object against each serialized object. So i implement a custom compare:
GenericMessage<?> incomeMessage = (GenericMessage<?>) object;
boolean removed = hazelcastInstance.getQueue(queueId).remove(object);
if (!removed) {
Iterator<Object> iterator = hazelcastInstance.getQueue(queueId).iterator();
while (iterator.hasNext()) {
Object next = iterator.next();
GenericMessage<?> message = (GenericMessage<?>) next;
if (incomeMessage.getHeaders().getKey()
.equals(message.getHeaders().getKey())) {
object = next;
removed = hazelcastInstance.getQueue(queueId).remove(object);
break;
}
}
}

Using of Class type variables as generics in Java [duplicate]

Is there a way in Java to have a map where the type parameter of a value is tied to the type parameter of a key? What I want to write is something like the following:
public class Foo {
// This declaration won't compile - what should it be?
private static Map<Class<T>, T> defaultValues;
// These two methods are just fine
public static <T> void setDefaultValue(Class<T> clazz, T value) {
defaultValues.put(clazz, value);
}
public static <T> T getDefaultValue(Class<T> clazz) {
return defaultValues.get(clazz);
}
}
That is, I can store any default value against a Class object, provided the value's type matches that of the Class object. I don't see why this shouldn't be allowed since I can ensure when setting/getting values that the types are correct.
EDIT: Thanks to cletus for his answer. I don't actually need the type parameters on the map itself since I can ensure consistency in the methods which get/set values, even if it means using some slightly ugly casts.
You're not trying to implement Joshua Bloch's typesafe hetereogeneous container pattern are you? Basically:
public class Favorites {
private Map<Class<?>, Object> favorites =
new HashMap<Class<?>, Object>();
public <T> void setFavorite(Class<T> klass, T thing) {
favorites.put(klass, thing);
}
public <T> T getFavorite(Class<T> klass) {
return klass.cast(favorites.get(klass));
}
public static void main(String[] args) {
Favorites f = new Favorites();
f.setFavorite(String.class, "Java");
f.setFavorite(Integer.class, 0xcafebabe);
String s = f.getFavorite(String.class);
int i = f.getFavorite(Integer.class);
}
}
From Effective Java (2nd edition) and this presentation.
The question and the answers made me come up with this solution: Type-safe object map. Here is the code. Test case:
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
public class TypedMapTest {
private final static TypedMapKey<String> KEY1 = new TypedMapKey<String>( "key1" );
private final static TypedMapKey<List<String>> KEY2 = new TypedMapKey<List<String>>( "key2" );
#Test
public void testGet() throws Exception {
TypedMap map = new TypedMap();
map.set( KEY1, null );
assertNull( map.get( KEY1 ) );
String expected = "Hallo";
map.set( KEY1, expected );
String value = map.get( KEY1 );
assertEquals( expected, value );
map.set( KEY2, null );
assertNull( map.get( KEY2 ) );
List<String> list = new ArrayList<String> ();
map.set( KEY2, list );
List<String> valueList = map.get( KEY2 );
assertEquals( list, valueList );
}
}
This is the Key class. Note that the type T is never used in this class! It's purely for the purpose of type casting when reading the value out of the map. The field key only gives the key a name.
public class TypedMapKey<T> {
private String key;
public TypedMapKey( String key ) {
this.key = key;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ( ( key == null ) ? 0 : key.hashCode() );
return result;
}
#Override
public boolean equals( Object obj ) {
if( this == obj ) {
return true;
}
if( obj == null ) {
return false;
}
if( getClass() != obj.getClass() ) {
return false;
}
TypedMapKey<?> other = (TypedMapKey<?>) obj;
if( key == null ) {
if( other.key != null ) {
return false;
}
} else if( !key.equals( other.key ) ) {
return false;
}
return true;
}
#Override
public String toString() {
return key;
}
}
TypedMap.java:
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class TypedMap implements Map<Object, Object> {
private Map<Object, Object> delegate;
public TypedMap( Map<Object, Object> delegate ) {
this.delegate = delegate;
}
public TypedMap() {
this.delegate = new HashMap<Object, Object>();
}
#SuppressWarnings( "unchecked" )
public <T> T get( TypedMapKey<T> key ) {
return (T) delegate.get( key );
}
#SuppressWarnings( "unchecked" )
public <T> T remove( TypedMapKey<T> key ) {
return (T) delegate.remove( key );
}
public <T> void set( TypedMapKey<T> key, T value ) {
delegate.put( key, value );
}
// --- Only calls to delegates below
public void clear() {
delegate.clear();
}
public boolean containsKey( Object key ) {
return delegate.containsKey( key );
}
public boolean containsValue( Object value ) {
return delegate.containsValue( value );
}
public Set<java.util.Map.Entry<Object, Object>> entrySet() {
return delegate.entrySet();
}
public boolean equals( Object o ) {
return delegate.equals( o );
}
public Object get( Object key ) {
return delegate.get( key );
}
public int hashCode() {
return delegate.hashCode();
}
public boolean isEmpty() {
return delegate.isEmpty();
}
public Set<Object> keySet() {
return delegate.keySet();
}
public Object put( Object key, Object value ) {
return delegate.put( key, value );
}
public void putAll( Map<? extends Object, ? extends Object> m ) {
delegate.putAll( m );
}
public Object remove( Object key ) {
return delegate.remove( key );
}
public int size() {
return delegate.size();
}
public Collection<Object> values() {
return delegate.values();
}
}
No, you can't do it directly. You'll need to write a wrapper class around Map<Class, Object> to enforce that Object will be instanceof Class.
It's possible to create a class which stores a map of type safe key to a value, and cast when necessary. The cast in get method is safe, as after using new Key<CharSequence>(), it's not possible to safely cast it to Key<String> or Key<Object>, so the type system enforces the correct usage of a class.
The Key class needs to be final, as otherwise an user could override equals and cause type-unsafety if two elements with different types were to be equal. Alternatively, it's possible to override equals to be final if you want to use inheritance despite the issues with it.
public final class TypeMap {
private final Map<Key<?>, Object> m = new HashMap<>();
public <T> T get(Key<? extends T> key) {
// Safe, as it's not possible to safely change the Key generic type,
// hash map cannot be accessed by an user, and this class being final
// to prevent serialization attacks.
#SuppressWarnings("unchecked")
T value = (T) m.get(key);
return value;
}
public <T> void put(Key<? super T> key, T value) {
m.put(key, value);
}
public static final class Key<T> {
}
}
You can use below 2 classes, Map class: GenericMap, Map-Key class: GenericKey
For example:
// Create a key includine Type definition
public static final GenericKey<HttpServletRequest> REQUEST = new GenericKey<>(HttpServletRequest.class, "HttpRequestKey");
public void example(HttpServletRequest requestToSave)
{
GenericMap map = new GenericMap();
// Saving value
map.put(REQUEST, requestToSave);
// Getting value
HttpServletRequest request = map.get(REQUEST);
}
Advantages
It forces the user to put and get correct types by compilation error
It's doing casing for you inside
Generic Key helps to avoid write the class type each time you calling put(..) or get
No typo mistakes, like if key is 'String' type
GenericMap
public class GenericMap
{
private Map<String, Object> storageMap;
protected GenericMap()
{
storageMap = new HashMap<String, Object>();
}
public <T> T get(GenericKey<T> key)
{
Object value = storageMap.get(key.getKey());
if (value == null)
{
return null;
}
return key.getClassType().cast(value);
}
/**
* #param key GenericKey object with generic type - T (it can be any type)
* #param object value to put in the map, the type of 'object' mast be - T
*/
public <T> void put(GenericKey<T> key, T object)
{
T castedObject = key.getClassType().cast(object);
storageMap.put(key.getKey(), castedObject);
}
#Override
public String toString()
{
return storageMap.toString();
}
}
GenericKey
public class GenericKey<T>
{
private Class<T> classType;
private String key;
#SuppressWarnings("unused")
private GenericKey()
{
}
public GenericKey(Class<T> iClassType, String iKey)
{
this.classType = iClassType;
this.key = iKey;
}
public Class<T> getClassType()
{
return classType;
}
public String getKey()
{
return key;
}
#Override
public String toString()
{
return "[classType=" + classType + ", key=" + key + "]";
}
}
T as a type must be defined generically in the class instance. The following example works:
public class Test<T> {
private Map<Class<T>, T> defaultValues;
public void setDefaultValue(Class<T> clazz, T value) {
defaultValues.put(clazz, value);
}
public T getDefaultValue(Class<T> clazz) {
return defaultValues.get(clazz);
}
}
Alternatively, you can use Paul Tomblin's answer, and wrap the Map with your own object which will enforce this type of generics.

Java reflection with clone

Example I have data layer after
public class DemoData implements Cloneable {
private String name;
private String value;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
#Override
protected Object clone() throws CloneNotSupportedException {
return super.clone(); //To change body of generated methods, choose Tools | Templates.
}
}
I want to assign data values (DemoData) to a duplicate data (DemoData clone) layer as follows
public static void main(String[] args) {
DemoData demoData = new DemoData();
demoData.setName("Class Sources");
testReflectionDemo(demoData);
}
private static DemoData testReflectionDemo(DemoData demoData) {
try {
DemoData clone = (DemoData) demoData.clone();
clone.setName(demoData.getName());
clone.setValue(demoData.getValue());
return clone;
} catch (CloneNotSupportedException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
I want to convert the method testReflectionDemo(DemoData demoData) to method testReflectionDemo(T t) reflection as shown below.I do not know how to continue, please help me
public <T> T testReflectionDemo(T t){
Class<?> aClass = t.getClass();
for (Method method : aClass.getMethods()) {
}
return null;
}
Thank you all for the help for my question,I've removed the clone method, I just applied reflection.Hi #dabaicai.Your code helped me with the idea,I thought passing the value to the private field would be easier a little.
public static <T> T clazzClone(T t) throws InstantiationException, IllegalAccessException, NoSuchFieldException {
Class<?> clazzRoot = t.getClass();
Object newInstance = clazzRoot.newInstance();
Field[] fieldsClone = newInstance.getClass().getDeclaredFields();
for (Field fieldClone : fieldsClone) {
fieldClone.setAccessible(true);
fieldClone.set(newInstance, getContent(t, fieldClone.getName()));
}
return (T) newInstance;
}
private static String getContent(Object aClass, String name) throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
Field declaredField = aClass.getClass().getDeclaredField(name);
declaredField.setAccessible(true);
return (String) declaredField.get(aClass);
}
My program means when I need to edit user input data to output the results I want,with a common filter function
fieldClone.set(newInstance,methodYourEdit(getContent(t, fieldClone.getName())));
If the argument of testReflectionDemo is a javabean,it means that the class of argument have several a pair method of setXXX and 'getXXX,and thegetXXXdon't have argument,thesetXXX` just have one argument.If is this,the following code can copy the property from old object to new object.
Class<?> aClass = t.getClass();
Object result = aClass.newInstance();
Map<String,MethodHolder> map=new HashMap<>();
for (Method method : aClass.getMethods()) {
if(method.getName().startsWith("get") && method.getParameterTypes().length==0){
String property=method.getName().substring(3);
MethodHolder hodler = map.get(property);
if(hodler ==null){
map.put(property, new MethodHolder(property, method, null));
continue;
}
hodler.getMethod=method;
}else if (method.getName().startsWith("set") && method.getParameterTypes().length==1) {
String property=method.getName().substring(3);
MethodHolder holder = map.get(property);
if(holder ==null){
map.put(property, new MethodHolder(property, null, method));
continue;
}
holder.setMethod=method;
}
}
List<MethodHolder> collect = map.values().stream().filter(item -> item.setMethod != null && item.getMethod != null).collect(Collectors.toList());
for (MethodHolder holder : collect) {
Object property = holder.getMethod.invoke(t);
holder.setMethod.invoke(result,property);
}
return (T)result;
The MethodHolder just have some field:
public static class MethodHolder{
private String property;
private Method getMethod;
private Method setMethod;
public MethodHolder() {
}
public MethodHolder(String property, Method getMethod, Method setMethod) {
this.property = property;
this.getMethod = getMethod;
this.setMethod = setMethod;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof MethodHolder)) return false;
MethodHolder that = (MethodHolder) o;
return Objects.equals(property, that.property);
}
#Override
public int hashCode() {
return Objects.hash(property);
}
}
Pay attention of that the following code just make shallow copy.

Android/Java Singleton with HashMap not keeping HashMap values

I'm using a Singleton to store a cache of objects but whenever I call the Singleton and add to the HashMap, it has no values.
The cache is checked at the beginning of a method (when the size is 1) but when adding to the HashMap again, the size of it is 0. The size of it therefore alternates between 0 and 1.
public class CachedObjects
{
static HashMap<String, Object> cachedObjects = new HashMap<>();
private static class InstanceHolder
{
private static final CachedObjects instance = new CachedObjects();
}
public static CachedObjects getInstance()
{
return CachedObjects.InstanceHolder.instance;
}
public void addObjectToCache(Object object)
{
cachedObjects.put(object.getTitle(), object);
}
public Object checkCacheForObject(String title)
{
Iterator it = cachedObjects.entrySet().iterator();
while (it.hasNext())
{
Map.Entry pair = (Map.Entry) it.next();
if (pair.getKey().equals(title))
{
return (Object) pair.getValue();
}
it.remove(); // avoids a ConcurrentModificationException
}
return null;
}
}
Where it's called:
public Object getObjectInfoFrom(String title)
{
Object cachedObjectCheck = CachedObjects.getInstance().checkCacheForObject(title);
// Size of HashMap is usually 1 here
if (cachedObjectCheck != null)
{
return cachedObjectCheck ;
}
// Lots of DB fetching here
Object object = new Object(DB details above);
CachedObjects.getInstance().addObjectToCache(object);
// The size of the HashMap always seems to be empty here
return object;
}
public class MyContext {
private static MyContext ourInstance = null;
private HashMap<String, String> translatedValue;
public static MyContext getInstance() {
if (ourInstance == null)
ourInstance = new MyContext();
return ourInstance;
}
private MyContext() {
translatedValue = new HashMap<>();
}
public void addTranslatedValue(String title, String value) {
translatedValue.put(title, value);
}
public String getTranslatedValue(String value) {
return translatedValue.get(value);
}
}
Using
MyContext.getInstance().addTranslatedValue("Next", valueTranslated);
System.out.println(myContext.getTranslatedValue("Next"));
Result
valueTranslated
First of all, this is not singleton because you have not hidden the constructor.
second, you need to remove this line:
it.remove(); // avoids a ConcurrentModificationException
Try this code, it works OK:
private static CachedObjectsClass singletonInstance = null;
HashMap<String, Object> cachedObjects;
private CachedObjectsClass()
{
cachedObjects = new HashMap<>();
}
public static CachedObjectsClass getInstance()
{
singletonInstance = singletonInstance == null ? new CachedObjectsClass()
: singletonInstance;
return singletonInstance;
}
public void addObjectToCache(String key, Object object)
{
cachedObjects.put(key, object);
}
public Object checkCacheForObject(String title)
{
return cachedObjects.get(title);
}
And usage:
Object cachedObjectCheck = CachedObjectsClass.getInstance()
.checkCacheForObject("kk");
CachedObjectsClass.getInstance().addObjectToCache("l", object);

ObjectifyGenericDao<T> with Objectify4

I want to leverage on the new features of Objectify4 however my application is build and is working with version 3. My application largely builds upon the ObjectifyGenericDao pattern and that the Objectify4 design pattern is quite different from this:
ObjectifyGenericDao.java
public class ObjectifyGenericDao<T> extends DAOBase
{
static final int BAD_MODIFIERS = Modifier.FINAL | Modifier.STATIC | Modifier.TRANSIENT;
static
{
// Register all your entity classes here
}
protected Class<T> clazz;
/**
* We've got to get the associated domain class somehow
*
* #param clazz
*/
protected ObjectifyGenericDao(Class<T> clazz)
{
this.clazz = clazz;
}
public ObjectifyGenericDao(ObjectifyOpts opts) {
super(opts);
//this.clazz = clazz;
}
public Key<T> put(T entity)
{
return ofy().put(entity);
}
// TODO This code was modified
// and need to be tested
public List<Key<T>> putAll(Iterable<T> entities)
{
Map<Key<T>, T> map = ofy().put(entities);
return new ArrayList<Key<T>>(map.keySet());
//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(String id) throws EntityNotFoundException
{
return ofy().get(this.clazz, id);
}
public T get(Key<T> key) throws EntityNotFoundException
{
return ofy().get(key);
}
/**
* 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;
}
// Added, but may not be really useful
public Query<T> query(String filter, String value) {
Query<T> q = ofy().query(clazz).filter(filter, value);
return q;
}
The bottleneck with Objectify4 is that it does not have DAOBase so it not very easy to migrate existing codes.
How can I have this pattern while using Objectify4 features?
As mentioned on the Objectify Google Group, just drop the extends DAOBase.
You can get code for OfyService here:
https://code.google.com/p/objectify-appengine/wiki/BestPractices
Add static import in ObjectifyGenericDao and then you can use methods like:
public Key<T> save(T entity){
return ofy().save().entity(entity).now();
}
public void delete(T entity){
ofy().delete().entity(entity);
}
public T get(Long id){
return ofy().load().type(clazz).id(id).get();
}
and so on ...

Categories

Resources