I am building generic methods for queries to the database with Hibernate, the following method consults the information of an entity by primary key.
#PersistenceContext(unitName = "UnitPers")
private EntityManager entity;
public Object findByPk(Class clazz, Object pk) throws Exception {
Object obj = null;
try {
obj = entity().find(clazz, pk);
} catch (Exception e) {
throw e;
}
return obj;
}
This method works correctly, but I do not want to make a cast (object to myTypeEntity) when making the call.
private myTypeEntity entity;
entity = (myTypeEntity) findByPk(myTypeEntity.class, new Bigdecimal("1"));
//GET and SET Methods
I want to avoid doing the cast when calling this method, bearing in mind that it is one of the purposes of the generic, but I have not managed to do it, any ideas? or what I intend to do is not possible.
You can use generics instead of using Object:
public <T> T findByPk(Class<T> clazz, Object pk) throws Exception {
T obj = null;
try {
obj = entity().find(clazz, pk);
} catch (Exception e) {
throw e;
}
return obj;
}
And then it should work without doing the cast
private myTypeEntity entity;
entity = findByPk(myTypeEntity.class, new Bigdecimal("1"));
By introducing a generic type variable on the method level you can define what type should be returned, this can be seen in #cpr4t3s' answer.
You can also shorten his snippet to the following:
public <T> T findByPk(Class<T> clazz, Object pk) throws Exception {
return entity().find(clazz, pk);
}
Because:
You're just throwing the exception up in the catch-block
You're doing nothing, but return the obj-variable
Related
I have the below member.
protected List<FieldHandler> fieldHandlers;
This list contains a list of concrete fieldHandler objects. Below is how values are added to this list.
fieldHandlers.add(new StringFieldHandler(fieldName));
Below is the FieldHandler object and a concrete implementation example.
public interface FieldHandler<T,R> {
R handle(R target, T fieldValue) throws JSONMapperException;
}
public class IntegerFieldHandler extends ValueFieldHandler<Integer,JSONObject> {
public IntegerFieldHandler(String fieldName) {
super(fieldName);
}
#Override
public JSONObject handle(JSONObject target, Integer fieldValue) throws JSONMapperException {
try {
target.put(fieldName, fieldValue);
} catch (JSONException ex) {
throw new JSONMapperException(ex);
//log the exception
}
return target;
}
}
Now I'm trying to get values from this list. Which could eventually be StringFieldHandlers or IntegerFieldHandlers or BooleanFieldHandlers.
FieldHandler fieldHandlerForCurrentHBaseColumnValue = fieldHandlers.get(i);
I need to check which handler this is and call the relevant handle method passing in the value.
I tried doing it this way but it seems ugly.
JSONObject targetObject = null;
FieldHandler fieldHandlerForCurrentHBaseColumnValue = fieldHandlers.get(i);
if (fieldHandlerForCurrentHBaseColumnValue instanceof IntegerFieldHandler) {
IntegerFieldHandler integerFieldHandler = (IntegerFieldHandler) fieldHandlerForCurrentHBaseColumnValue;
targetObject = integerFieldHandler.handle(targetObject,(Integer) tuple.get(i));
} else if (fieldHandlerForCurrentHBaseColumnValue instanceof BooleanFieldHandler) {
} else if (fieldHandlerForCurrentHBaseColumnValue instanceof StringFieldHandler) {
}
How can I do this? Any help would be much appreciated.
I want tranfers attributes values from a object that came from my Entity manager to a new object.
The return Object is always null
public class ReflectionUtil {
public static Object copyAttributesFromTo(Object a, Object b) throws IllegalArgumentException, IllegalAccessException {
Field[] fieldsFromFirstClass = a.getClass().getDeclaredFields();
Field[] fieldsFromSecondClass = b.getClass().getDeclaredFields();
for (Field currentFieldFromTheFirstClass : fieldsFromFirstClass) {
for (Field currentFieldFromTheSecondClass : fieldsFromSecondClass) {
String nameOfTheFirstField = currentFieldFromTheFirstClass.getName();
String nameOfTheSecondField = currentFieldFromTheSecondClass.getName();
if (!Modifier.isFinal(currentFieldFromTheFirstClass.getModifiers())) {//Dispensa os Final
if (!currentFieldFromTheFirstClass.isAnnotationPresent(Id.class)) {//Não sobescreve campo id
if (nameOfTheFirstField.equals(nameOfTheSecondField)) {
currentFieldFromTheFirstClass.setAccessible(true);
currentFieldFromTheSecondClass.setAccessible(true);
currentFieldFromTheSecondClass.get(b));
currentFieldFromTheFirstClass.set(a, currentFieldFromTheSecondClass.get(b));
}
}
}
}
}
return a;
}
}
In the Facade call I always have to put all the attribute values to new object
public void update(Profile object) {
dao.beginTransaction();
Profile persistedObject = dao.find(object.getId());
persistedObject.setName(object.getName());
dao.commitAndCloseTransaction();
}
So I think to create some like that
public void update(Profile object) {
dao.beginTransaction();
Profile persistedObject = dao.find(object.getId());
ReflectionUtil.copyAttributesFromTo(persistedObject , object);
dao.commitAndCloseTransaction();
}
really miss understood why u are using 2 loop? .. if the classes are same . u dont need to do it .. just do it in 1 loop .. and use fields get for obj which is holding data .. and use set for to set .. here is the more better way .. if the same object is required u can use generics .. and same object type will be required ( request return type )
public static <T> T copyAttributesFromTo(T value, T dataHolder) throws IllegalArgumentException, IllegalAccessException {
if (value == null || dataHolder == null) {
throw new IllegalArgumentException();
}
final Field[] fields = value.getClass().getDeclaredFields();
for (Field field : fields) {
if (!Modifier.isFinal(field.getModifiers())) {
field.setAccessible(true);
field.set(value, field.get(dataHolder));
}
}
return value;
}
The return Object is always null
It is impossible for the return object (i.e. whatever a contains when you return) to be null.
It is easy to see that the code does not change the reference a. There are no assignments to it in the method, so it cannot change.
The other possibility was that you called the method with a null value for a. But if you did that, the first line of the method calls a.getClass() and that will throw an NPE if a is null.
TL;DR - it is impossible.
So what does this mean?
Here are the most likely explanations:
You are mistaken that null is being returned. Perhaps the method is not being called? Perhaps, it is not returning?
Maybe you have misinterpreted the evidence in some other way. It is hard to know without seeing the code ... and the evidence.
Maybe you don't mean that the method is returning Object; i.e. I misunderstood the question. (Your problem description is pretty unambiguous though ...)
I make a change in the code and works to update for me
public static Object copyAttributesFromTo(Object a, Object b) throws IllegalArgumentException, IllegalAccessException {
Field[] fieldsFromFirstClass = a.getClass().getDeclaredFields();
Field[] fieldsFromSecondClass = b.getClass().getDeclaredFields();
//JSFMessageUtil.addMsgLog(JSFMessageUtil.matricula, ReflectionUtil.class.getCanonicalName(), "ReflectionUtil: Aqui");
for (Field currentFieldFromTheFirstClass : fieldsFromFirstClass) {
for (Field currentFieldFromTheSecondClass : fieldsFromSecondClass) {
Object nameOfTheFirstField = currentFieldFromTheFirstClass.getName();
Object nameOfTheSecondField = currentFieldFromTheSecondClass.getName();
if (!Modifier.isFinal(currentFieldFromTheFirstClass.getModifiers())) {//Dispensa os Final
//if (!currentFieldFromTheFirstClass.isAnnotationPresent(Id.class)) {//Não sobescreve campo id
if (nameOfTheFirstField.equals(nameOfTheSecondField)) {
currentFieldFromTheFirstClass.setAccessible(true);
currentFieldFromTheSecondClass.setAccessible(true);
//JSFMessageUtil.addMsgLog(JSFMessageUtil.matricula, ReflectionUtil.class.getCanonicalName(), "ReflectionUtil: " + currentFieldFromTheSecondClass.get(b));
currentFieldFromTheFirstClass.set(a, currentFieldFromTheSecondClass.get(b));
}
//}
}
}
}
return a;
}
The call
public void update(Aluno a) {
try {
Aluno aluno = new Aluno();//(Aluno) em.find(Aluno.class, a.getId());
em.getTransaction().begin();
//aluno.setNome(a.getNome());
ReflectionUtil.copyAttributesFromTo(aluno, a);
em.merge(aluno);
em.getTransaction().commit();
} catch (Exception e) {
System.out.println("Error " + e.getLocalizedMessage());
JOptionPane.showMessageDialog(null, e.getLocalizedMessage(), "Erro", JOptionPane.ERROR_MESSAGE);
} finally {
em.close();
}
}
First I want to say that yes - I know there are ORMs like Morphia and Spring Data for MongoDB. I'm not trying to reinvent the weel - just to learn. So basic idea behind my AbstractRepository is to encapsulate logic that's shared between all repositories. Subclasses (repositories for specific entities) passes Entity class to .
Converting entity beans (POJOs) to DBObject using Reflection was pretty streightforward. Problem comes with converting DBObject to entity bean. Reason? I need to convert whatever field type in DBObject to entity bean property type. And this is where I'm stuck. I'm unable to get entity bean class in AbstractRepository method T getEntityFromDBObject(DBObject object)
I could pass entity class to this method but that would defeat the purpose of polymorphism. Another way would be to declare private T type property and then read type using Field. Defining additional property just so I can read doesn't sound right.
So the question is - how would you map DBObject to POJO using reflection using less parameteres possible. Once again this is the idea:
public abstract class AbstractRepository<T> {
T getEntityFromDBObject(DBObject object) {
....
}
}
And specific repository would look like this:
public class EntityRepository extends AbstractRepository<T> {
}
Thanks!
Note: Ignore complex relations and references. Let's say it doesn't need to support references to another DBObjects or POJOs.
You need to build an instance of type T and fill it with the data that comes in ´DBObject´:
public abstract class AbstractRepository<T> {
protected final Class<T> entityClass;
protected AbstractRepository() {
// Don't remember if this reflection stuff throws any exception
// If it does, try-catch and throw RuntimeException
// (or assign null to entityClass)
// Anyways, it's impossible that such exception occurs here
Type t = this.getClass().getGenericSuperclass();
this.entityClass = ((Class<T>)((ParameterizedType)t).getActualTypeArguments()[0]);
}
T getEntityFromDBObject(DBObject object) {
// Use reflection to create an entity instance
// Let's suppose all entities have a public no-args constructor (they should!)
T entity = (T) this.entityClass.getConstructor().newInstance();
// Now fill entity with DBObject's data
// This is the place to fill common fields only, i.e. an ID
// So maybe T could extend some abstract BaseEntity that provides setters for these common fields
// Again, all this reflection stuff needs to be done within a try-catch block because of checked exceptions
// Wrap the original exception in a RuntimeException and throw this one instead
// (or maybe your own specific runtime exception for this case)
// Now let specialized repositories fill specific fields
this.fillSpecificFields(entity, object);
return entity;
}
protected abstract void fillSpecificFields(T entity, DBObject object);
}
If you don't want to implement the method .fillSpecificFields() in every entity's repository, then you'd need to use reflection to set every field (including common ones such as ID, so don't set them manually).
If this is the case, you already have the entity class as a protected attribute, so it's available to every entity's repository. You need to iterate over ALL its fields, including the ones declared in superclasses (I believe you have to use method .getFields() instead of .getDeclaredFields()) and set the values via reflection.
As a side note, I really don't know what data comes in that DBObject instance, and in what format, so please let me know if extracting fields' values from it results to be non trivial.
First I want to apologies for answering to your comments almost two months later. I did managed to figure it out on my own and here is how I've implemented it (and tested) so maybe someone will make a use of it:
public abstract class AbstractRepository<T> {
#Inject
private MongoConnectionProvider provider;
// Keeps current repository collection name
protected String collectionName;
#PostConstruct
public abstract void initialize();
public String getCollectionName() {
return this.collectionName;
}
protected void setCollectionName(String collectionName) {
this.collectionName = collectionName;
}
protected DBCollection getConnection() {
DB conn = this.provider.getConnection();
DBCollection collection = conn.getCollection(this.collectionName);
return collection;
}
private void putFieldToDbObject(T source, DBObject target, Field field) {
// TODO: Think more elegant solution for this
try {
field.setAccessible(true);
// Should we cast String to ObjectId
if (field.getName() == "id" && field.get(source) != null
|| field.isAnnotationPresent(DBRef.class)) {
String key = field.getName().equals("id") ? "_id" : field.getName();
target.put(key, new ObjectId(field.get(source).toString()));
} else {
if(!field.getName().equals("id")) {
target.put(field.getName(), field.get(source));
}
}
} catch (IllegalArgumentException | IllegalAccessException exception) {
// TODO Auto-generated catch block
exception.printStackTrace();
} finally {
field.setAccessible(false);
}
}
#SuppressWarnings("rawtypes")
protected DBObject getDbObject(T entity) {
DBObject result = new BasicDBObject();
// Get entity class
Class entityClass = entity.getClass();
Field[] fields = entityClass.getDeclaredFields();
// Update DBobject with entity data
for (Field field : fields) {
this.putFieldToDbObject(entity, result, field);
}
return result;
}
#SuppressWarnings({ "unchecked", "rawtypes" })
public T getEntityFromDBObject(DBObject object) throws MappingException {
Type superclass = this.getClass().getGenericSuperclass();
Type entityClass = ((ParameterizedType) superclass).getActualTypeArguments()[0];
T entity;
try {
entity = ((Class<T>) entityClass).newInstance();
// Map fields to entity properties
Set<String> keySet = object.keySet();
for(String key : keySet) {
String fieldName = key.equals("_id") ? "id" : key;
Field field = ((Class<T>) entityClass).getDeclaredField(fieldName);
field.setAccessible(true);
if(object.get(key).getClass().getSimpleName().equals("ObjectId")) {
field.set(entity, object.get(key).toString());
} else {
// Get field type
Type fieldType = field.getType();
Object fieldValue = object.get(key);
Class objectType = object.get(key).getClass();
if(!fieldType.equals(objectType)) {
// Let's try to convert source type to destination type
try {
fieldValue = (((Class) fieldType).getConstructor(objectType)).newInstance(object.get(key));
} catch (NoSuchMethodException exception) {
// Let's try to use String as "man-in-the-middle"
String objectValue = object.get(key).toString();
// Get constructor for destination type that take String as parameter
Constructor constructor = ((Class) fieldType).getConstructor(String.class);
fieldValue = constructor.newInstance(objectValue);
}
}
field.set(entity, fieldValue);
}
field.setAccessible(false);
}
} catch (InstantiationException | IllegalAccessException | NoSuchFieldException | SecurityException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException e) {
throw new MappingException(e.getMessage(), MappingExceptionCode.UNKNOWN_ERROR);
}
return entity;
}
public List<T> getAll() {
DBCollection conn = this.getConnection();
DBCursor cursor = conn.find();
List<T> result = new LinkedList<T>();
while (cursor.hasNext()) {
DBObject obj = cursor.next();
try {
result.add(this.getEntityFromDBObject(obj));
} catch (MappingException e) {
}
}
return result;
}
public T getOneById(String id) {
DBObject idRef = new BasicDBObject().append("_id", new ObjectId(id));
DBCollection conn = this.getConnection();
DBObject resultObj = conn.findOne(idRef);
T result = null;
try {
result = this.getEntityFromDBObject(resultObj);
} catch (MappingException e) {
}
return result;
}
public void save(T entity) {
DBObject object = this.getDbObject(entity);
DBCollection collection = this.getConnection();
collection.save(object);
}
}
You've stumbled onto the problem of object mapping. There are a few libraries out there that look to help with this. You might check out ModelMapper (author here).
How to do the following properly in Java? I would like to have a generic routine that can create a list of objects. In this routine I expect the constructor of the class of these objects to support a particular parameter.
To clarify: I would like this routine to create a List<T> from a JSON string. This is part of a larger deserialization code. If I can somehow specify that each supported T implements a constructor that creates T given a JSONObject, then I could write the routine something like this:
interface CreatableFromJSONObject<T> {
T(JSONObject object); // Complains about missing return type.
}
static <T> List<T extends CreatableFromJSONObject> jsonArrayToList(JSONArray array) {
List<T> result = new ArrayList<T>();
for (int i = 0; i < array.length; ++i) {
JSONObject jsonObject = array.getJSONObject(i);
result.add(T(jsonObject)); // If T has one constructor with 1 one argument JSONObject
}
return result;
}
and then with an example class that implements this interface
class SomeClass implements CreatableFromJSONObject {
SomeClass(JSONObject object) throws JSONException {
// implementation here
}
}
I could use the desired method as:
List<SomeClass> list = jsonArrayToList<SomeClass>(someJSONArray);
Now, there are quite some hits on this on StackOverflow, so there I have learned that what I outlined above is not possible because Java does not support specifying a particular constructor in an interface and also not for static methods (which would be an alternative route to the same thing and not possible for the same reason).
So, what is then the best way of achieving this?
My current best attempt is the following:
public static <T> List<T> jsonArrayToList(final JSONArray jsonArray, Constructor<T> fromJSONObjectConstructor) {
List<T> result = new ArrayList<T>();
try {
for (int i = 0; i < jsonArray.length(); i++) {
result.add(fromJSONObjectConstructor.newInstance(jsonArray.getJSONObject(i)));
}
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (JSONException e) {
throw new RuntimeException(e);
}
return result;
}
and then to add to each class that should be supported by this method:
public class SomeClass {
public static final Constructor<SomeClass> jsonObjectConstructor;
static {
try {
jsonObjectConstructor = CafellowEntity.class.getConstructor(JSONObject.class);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
SomeClass(JSONObject object) throws JSONException {
// Implementation here
}
}
which I use as
List<SomeClass> list = jsonArrayToList(myJSONArray, SomeClass.jsonObjectConstructor);
It is the most pretty solution I could come up with apart from not using a generic implementation at all and just put the (in this case) couple of lines of code that is actually doing the work in the routine wherever I need them for a particular class.
Any suggestions? What about the performance of this versus alternative solutions? By not supporting it just like this Java is probably telling me I should not be wanting to do this, but that does not prevent me from wondering about it anyway.
Unless you are doing some kind of unusual deserialization this design is overly-complicated and error prone. Android bundles an excellent JSON parser that can already do this, and do it well. Each type that you are currently defining custom constructors for can be deserialized with a single line of code:
final CustomObj obj = new Gson().fromJson(jsonObj.toString(), CustomObj.class);
Incorporating this into your existing method, you end up with this:
public static <T> List<T> jsonArrayToList(final JSONArray jsonArray,
Class<T> clazz) {
if (jsonArray == null || clazz == null)
return null;
final Gson gson = new Gson();
List<T> result = new ArrayList<T>(jsonArray.length());
for (int i = 0; i < jsonArray.length(); i++) {
try {
result.add(gson.fromJson(jsonArray.getJSONObject(i).toString(),
clazz));
} catch (final JSONException je) {
je.printStackTrace();
return null;
}
}
return result;
}
You may simplify your solution by omitting the constructors instances and using the clazz instances instead. So the signature of jsonArrayToList() would be:
public static <T> List<T> jsonArrayToList(final JSONArray jsonArray, Class<T> clazz);
and then calling the constructor by clazz.newInstance();
This would work if you know the type of the class in advance.
The following two methods are used to wrap deserialization using Google Gson:
public static <T> T Deserialize(String jsonData, Type t) {
T obj = null;
try {
obj = new Gson().fromJson(jsonData, t);
} catch (Exception e) {
Log.e(DEBUG_TAG, e.getMessage());
}
return obj;
}
public static <T> T Deserialize(String jsonData, Class<T> toClass) {
T obj = null;
try {
obj = new Gson().fromJson(jsonData, toClass);
} catch (Exception e) {
Log.e(DEBUG_TAG, e.getMessage());
}
return obj;
}
They are almost identical, but I can't figure out a smart way to get rid of the duplicated code.
Any suggestions?
Class implements the interface Type, so it looks like only having the first method should be sufficient.
EDIT: actually it looks like these methods are implemented separately for a reason. At least read the javadoc to understand why before refactoring. Thanks to home for pointing this out.
Type is an interface implemented by Class, so you could get rid of the second method completely.