new generic object problem [duplicate] - java

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Create instance of generic type in Java?
public class MyCache <T extends Taxable> {
private Map<Long, T> map = new HashMap<Long, T>();
public void putToMap(Long nip, T t){
map.put(nip, t);
}
public T getFromMap(Long nip){
return map.get(nip);
}
}
public class TaxableFactory<T extends Taxable> {
private MyCache<T> cache;
public void setCache(MyCache<T> cache) {
this.cache = cache;
}
public TaxableFactory() {
}
public void putT(T t) {
cache.putToMap(t.getNip(), t);
}
public T get(long nip) throws InstantiationException, IllegalAccessException {
T myT = cache.getFromMap(nip);
if (myT == null) {
T newT ;
putT(newT);
return null;
} else
return myT;
}
I tried many ways to create new T in my get method. Seems like I need little help :) How to do it to m ake it work?

Even though you are using generics, you still would need to pass the Class as an argument if you want to obtain a new Instance of T.
public T get(Class<T> clazz, long nip) throws InstantiationException, IllegalAccessException {
T myT = cache.getFromMap(nip);
if (myT == null) {
T newT = clazz.newInstance();
putT(newT);
return newT;
} else
return myT;
}
You would then call it like this:
.get(SomeTaxable.class, someNip)

Related

Storing a class in a variable Spring boot

I want to pass a class as an argument so List changes dynamically, I've tried lots of things but none of them have worked out, I don't even know if it's actually possible in Java.
Any advice?
public class QueryMapper {
protected Object targetClass;
public QueryMapper(Object targetClass) {
this.targetClass = targetClass;
}
public Object getTargetClass() {
// targetClass;
return targetClass.getClass();
}
public void setTargetClass(Object targetClass) {
this.targetClass = targetClass;
}
public List<targetClass> mapper(Query q) {
NativeQueryImpl nativeQuery = (NativeQueryImpl) q;
nativeQuery.setResultTransformer(AliasToEntityMapResultTransformer.INSTANCE);
List<Map<String, targetClass>> result = nativeQuery.getResultList();
return q.getResultList();
}
}

How generify class with T and List<T>

I am trying to generify my class structure.
I will show my real structure to be more specific.
I am writing application with offline mode support, so I decided to implement my ETag cache mechanism in using Robospice and GreenDao ORM.
I need to cache only GET requests.
Firstly my requests should extend base request(not mine), in my case RetrofitSpiceRequest<T, V>
T is type of return data
V is service type, in my case I am using Retrofit.
The problem is that return type is not List of T types by default and I need to create subclass that extends array of T objects and that use it as return type.
Something like this
public class City {
....
....
....
public static class List extends ArrayList<City> {
.....
.....
}
}
And use City.List as return type.
But I have my DAO declared as following
public class CityDao extends AbstractDao<City, Long> {
}
In each request (GET) I need to have specific DAO as a member in order to cache data if it differs from the server data. Or load data from the local database if there is no connection.
The problem here is that request generified by T type which is mostly list, City.List in my case, of some objects, but my dao is generified by, for example E type which is City in my case.
I want to create method like this
public AbastractDao<T,Long> getRequestDao() {
}
But as far as my Request returns City.List, I have no idea how to generify this class, I feel that it is possible, but now no ideas.
In case of non generic dao method, I have to duplicate code like this
#Override
public void insertReceivedData(City.List received) {
mCityDao.insertOrReplaceInTx(received);
}
#Override
public City.List getCachedData() {
if (mFilterMap != null && mFilterMap.size() > 0) {
return (City.List) mCityDao.loadAll();
} else {
WhereCondition[] whereConditions = QueryUtils.convertPropertyMapToConditionalArray(mFilterMap);
return (City.List) mCityDao.queryBuilder().where(whereConditions[0], Arrays.copyOfRange(whereConditions, 1, whereConditions.length)).list();
}
}
In each request
Please share your ideas.
Thanks.
I end up with following solution. It is not as good as I wanted, but it works and better than duplicating code.
My base request class.
public abstract class BaseGetRequest<L extends List<T>, T, V> extends RetrofitSpiceRequest<L, V> implements FilterableRequest {
// Context
protected Context mContext;
// Filter used in request and in queries
protected Map<Property, String> mFilterMap;
// Session provided Singletone
protected DaoSessionProvider mSessionProvider;
public BaseGetRequest(Class<L> clazz, Class<V> retrofitedInterfaceClass, Context context, Map<Property, String> filterMap) {
super(clazz, retrofitedInterfaceClass);
mContext = context;
mFilterMap = filterMap;
mSessionProvider = ((DaoSessionProvider) mContext.getApplicationContext());
// TODO determine required retry count
setRetryPolicy(new RetryPolicy() {
#Override
public int getRetryCount() {
return 0;
}
#Override
public void retry(SpiceException e) {
}
#Override
public long getDelayBeforeRetry() {
return 0;
}
});
}
protected WhereCondition[] getWhereConditions() {
return QueryUtils.convertPropertyMapToConditionalArray(mFilterMap);
}
public BaseGetRequestV2(Class<L> clazz, Class<V> retrofitedInterfaceClass, Context context) {
this(clazz, retrofitedInterfaceClass, context, null);
}
public abstract AbstractDao<T, Long> getDao();
public abstract L createDataList(List<T> list);
public L getCachedData() {
if (mFilterMap != null && mFilterMap.size() > 0) {
WhereCondition[] whereConditions = getWhereConditions();
return createDataList(getDao().queryBuilder().where(whereConditions[0], Arrays.copyOfRange(whereConditions, 1, whereConditions.length)).list());
} else {
return createDataList(getDao().loadAll());
}
}
public abstract L getData();
#Override
public Map<Property, String> getFilterMap() {
return mFilterMap;
}
public Map<String, String> getStringMap() {
return QueryUtils.convertPropertyMapToString(mFilterMap);
}
#Override
public L loadDataFromNetwork() throws Exception {
L receivedData = null;
try {
receivedData = getData();
WhereCondition[] conditions = getWhereConditions();
getDao().queryBuilder().where(conditions[0],Arrays.copyOfRange(conditions, 1, conditions.length)).buildDelete().executeDeleteWithoutDetachingEntities();
getDao().insertOrReplaceInTx(receivedData);
} catch (Exception ex) {
receivedData = getCachedData();
}
return receivedData;
}
}
And I can extend this class like so:
public class NewsRequest extends BaseGetRequest<NewsArticle.List, NewsArticle, API> {
public static final String TARGET_URL = "/news";
NewsArticleDao mNewsArticleDao;
public NewsRequest(Context context) {
this(context, null);
}
public NewsRequest(Context context, Map<Property, String> filterMap) {
super(NewsArticle.List.class, API.class, context, filterMap);
mNewsArticleDao = mSessionProvider.getDaoSession().getNewsArticleDao();
}
#Override
public AbstractDao<NewsArticle, Long> getDao() {
return mNewsArticleDao;
}
#Override
public NewsArticle.List createDataList(List<NewsArticle> list) {
return new NewsArticle.List(list);
}
#Override
public NewsArticle.List getData() {
return getService().getNews(getStringMap());
}
}

How can I make an i18n compliant EnumTypeAdapter?

I'm working on a nice solution to internationalize Enums by Gson deserialize (.toJson).
For now I have it:
private static final class GenericEnumTypeAdapter<T extends Enum<T>> extends TypeAdapter<T> {
private ResourceBundle bundle = ResourceBundle.getBundle("Messages");
private Class<T> classOfT;
public GenericEnumTypeAdapter(Class<T> classOfT) {
this.classOfT = classOfT;
}
public T read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
return Enum.valueOf(classOfT, in.nextString());
}
public void write(JsonWriter out, T value) throws IOException {
out.value(value == null ? null : bundle.getString("enum." + value.getClass().getSimpleName() + "."
+ value.name()));
}
}
The problem of this solution is: For each enum you should register a new Adapter:
gsonBuilder.registerTypeAdapter(EventSensorState.class,
new GenericEnumTypeAdapter<>(FirstEnum.class)
Do someone has an idea to do it better?
Use a TypeAdapterFactory to generate ALL the Adapters. See How do I implement TypeAdapterFactory in Gson?
To convert your TypeAdapter into a TypeAdapterFactory, the key is detecting the class properly, and then using the create method. Warning: this solution will register every type of Enum in your system; you may have to tweak it to only work with Enums that implement a particular interface, or register Enum classes with the subclass, etc. I created an EnumGenerator class to do most of the work of the reading conversion, which you should be able to figure out on your own.
public class EnumAdapterFactory implements TypeAdapterFactory {
private final ResourceBundle bundle;
private final EnumGenerator generator;
public EnumAdapterFactory(ResourceBundle bundle, EnumGenerator generator) {
this.bundle = bundle;
this.generator = generator;
}
#SuppressWarnings("unchecked")
#Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
if (!Enum.class.isAssignableFrom(type.getRawType())) return null;
return (TypeAdapter<T>) new GenericEnumTypeAdapter();
}
private final class GenericEnumTypeAdapter<T extends Enum<T>> extends TypeAdapter<T> {
public T read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
return generator.create(in.nextString());
}
public void write(JsonWriter out, T value) throws IOException {
if(value == null) {
out.nullValue();
return;
}
out.value(bundle.getString("enum."
+ value.getClass().getSimpleName() + "."
+ value.name()));
}
}
}
And EnumGenerator's interface:
public interface EnumGenerator {
<T extends Enum<T>> T create(String nextString);
}

Keeping possible exceptions in Enum

I am working on some workflow and it is possible to raise many exceptions in that. I heard that we can keep all those possible exceptions in an Enum (Exception1, Exception2 ...) and use it. How can we do that using Enums in Java?
You can add the classes of exceptions with
enum EnumWithExceptions {
ENUM1(Exception1.class, Exception2.class),
ENUM2(Exception3.class);
private final Class<? extends Exception>[] exceptions;
private EnumWithExceptions(Class<? extends Exception>... exceptions) {
this.exceptions = exceptions;
}
public boolean matches(Exception e) {
for(Class<? extends Exception> e2: exceptions)
if (e2.isInstance(e)) return true;
return false;
}
}
} catch(Exception e){
if (ENUM1.matches(e)){
//do something
} else if(ENUM2.matches(e)) {
//do something
} else {
//do something
}
}
enum Fred {
SAM(AnException.class),
I(AnotherException.class),
AM(YetAnotherException.class)
;
private Throwable t;
Fred(Throwable throwable) {
this.t = throwable;
}
public Throwable getThrowable() {
return t;
}
}
...
throw Fred.SAM.getThrowable();
Why not store the exceptions in an ArrayList? Or if you want to name the index, you could use a HashMap.
import java.util.ArrayList;
import java.util.HashMap;
public final class ExceptionStorage {
private static int exceptionCount = 0;
private static HashMap<String, Exception> indexedExceptions = new HashMap<>();
private static ArrayList<Exception> exceptions = new ArrayList();
public static void addException(Exception e) {
exceptions.add(e);
}
public static void putException(Exception e) {
indexedExceptions.put("Exception" + (++exceptionCount), e);
}
public static ArrayList<Exception> getUnindexedExceptions() {
return this.exceptions;
}
public static HashMap<String, Exception> getIndexedExceptions() {
return this.indexedExceptions;
}
}
Obviously you would have to modify the code to use either ArrayList or HashMap, but I think this would be a better solution than using Enums.

Access generic type parameter at runtime?

Event dispatcher interface
public interface EventDispatcher {
<T> EventListener<T> addEventListener(EventListener<T> l);
<T> void removeEventListener(EventListener<T> l);
}
Implementation
public class DefaultEventDispatcher implements EventDispatcher {
#SuppressWarnings("unchecked")
private Map<Class, Set<EventListener>> listeners = new HashMap<Class, Set<EventListener>>();
public void addSupportedEvent(Class eventType) {
listeners.put(eventType, new HashSet<EventListener>());
}
#Override
public <T> EventListener<T> addEventListener(EventListener<T> l) {
Set<EventListener> lsts = listeners.get(T); // ****** error: cannot resolve T
if (lsts == null) throw new RuntimeException("Unsupported event type");
if (!lsts.add(l)) throw new RuntimeException("Listener already added");
return l;
}
#Override
public <T> void removeEventListener(EventListener<T> l) {
Set<EventListener> lsts = listeners.get(T); // ************* same error
if (lsts == null) throw new RuntimeException("Unsupported event type");
if (!lsts.remove(l)) throw new RuntimeException("Listener is not here");
}
}
Usage
EventListener<ShapeAddEvent> l = addEventListener(new EventListener<ShapeAddEvent>() {
#Override
public void onEvent(ShapeAddEvent event) {
// TODO Auto-generated method stub
}
});
removeEventListener(l);
I've marked two errors with a comment above (in the implementation). Is there any way to get runtime access to this information?
No, you can't refer 'T' at runtime.
http://java.sun.com/docs/books/tutorial/java/generics/erasure.html
update
But something like this would achieve similar effect
abstract class EventListener<T> {
private Class<T> type;
EventListener(Class<T> type) {
this.type = type;
}
Class<T> getType() {
return type;
}
abstract void onEvent(T t);
}
And to create listener
EventListener<String> e = new EventListener<String>(String.class) {
public void onEvent(String event) {
}
};
e.getType();
You can't do it in the approach you are trying, due to erasure.
However, with a little change in the design I believe you can achieve what you need. Consider adding the following method to EventListener interface:
public Class<T> getEventClass();
Every EventListener implementation has to state the class of events it works with (I assume that T stands for an event type). Now you can invoke this method in your addEventListener method, and determine the type at runtime.

Categories