I'm using the method below to get the names of all getter methods of a class:
private static Map<String, Object> fetchGetterMethods(Object object) {
Map<String, Object> result = new HashMap<String, Object>();
BeanInfo info;
try {
info = Introspector.getBeanInfo(object.getClass());
for (PropertyDescriptor pd : info.getPropertyDescriptors()) {
Method reader = pd.getReadMethod();
if (reader != null) {
String name = pd.getName();
if (!"class".equals(name)) {
try {
Object value = reader.invoke(object);
result.put(name, value);
} catch (Exception e) {
}
}
}
}
} catch (IntrospectionException e) {
} finally {
return result;
}
}
I would like to skip the getter methods annotated with #Transient. How can I implement this?
#Transient
public boolean isValid() {
}
All you need is reader.getAnnotation(Transient.class) - if that returns something (it'll be an instance of Transient), it had the annotation. If it returns null, it did not. You can only do this to annotations whose definition is explicitly annotated with retentionlevel runtime, but assuming you're talking about JPA's #Transient, it is.
Note that writing a return statement in a finally block is absolutely not something you want to do.
You should use the Method#isAnnotationPresent method.
if (!reader.isAnnotationPresent(Transient.class)) {
// do work
}
This is a convenience method for the solution suggested by #rzwitserloot, and is the equivalent to:
if (reader.getAnnotation(Transient.class) == null) {
Related
I'm rewriting a framework originally done in C# into Java and this has me stumped. It's a method using reflection to return any property in a class that implements a particular interface using LINQ:
public List<TInterface> GetElementsOfType<TInterface>()
{
return GetType().GetProperties()
.Where(x => typeof(TInterface).IsAssignableFrom(x.PropertyType))
.Select(x => x.GetValue(this, null)).OfType<TInterface>()
.ToList();
}
I am trying to recreate in Java and so far have this. Not too sure if it's right though?:
public <T> List<?> GetElementsOfType(Class<T> klazz) {
Class<?> props = this.getClass();
List<T> elementsOfType = new ArrayList<>();
try {
Field fieldlist[] = props.getDeclaredFields();
for (Field aFieldlist : fieldlist) {
if (aFieldlist.getType().isAssignableFrom(klazz)){
elementsOfType.add((T)aFieldlist);
}
}
} catch (Exception e) {
return null;
}
return elementsOfType;
}
Update: Thanks everyone for your help. This seems to work for me although the unchecked cast causes a warning I had to suppress:
#SuppressWarnings("unchecked")
public <T> List<T> GetElementsOfType(Class<T> klazz) {
Class<?> props = this.getClass();
List<T> elementsOfType = new ArrayList<>();
try {
Field fieldlist[] = props.getDeclaredFields();
for (Field aFieldlist : fieldlist) {
if (klazz.isAssignableFrom(aFieldlist.getType())){
elementsOfType.add((T) aFieldlist.get(this));
}
}
} catch (Exception e) {
return elementsOfType;
}
return elementsOfType;
}
}
In Java, a property is not a field. A property is defined as a public non-static read method and, if it’s not a read-only property, a public non-static write method. An instance of a class with one or more such properties is known as a Java bean.
You can examine properties using the java.beans package, starting with Introspector:
try {
BeanInfo beanInfo = Introspector.getBeanInfo(props, Object.class);
for (PropertyDescriptor prop : beanInfo.getPropertyDescriptors()) {
if (klazz.isAssignableFrom(prop.getPropertyType())) {
elementsOfType.add(klazz.cast(prop.getReadMethod().invoke(this)));
}
}
} catch (IntrospectionException | ReflectiveOperationException e) {
throw new RuntimeException(e);
}
Because Java uses checked exceptions, you can’t easily use Streams to write LINQ-like code in this case. It’s possible, but unwieldy. And not worth the bother, considering the above code is fairly succinct.
(The reason for the Object.class in Introspector.getBeanInfo(klazz, Object.class) is that we don’t want properties of Object, namely the read-only class property of Object defined by Object.getClass().)
I have a piece of code, it's always used but it looked very redundant , and what can I do for sidestepping redundancy.
if(CommonUtil.isNull(second.getProvince())) {
second.setProvince(first.getProvince());
}
if(CommonUtil.isNull(second.getCity())) {
second.setCity(first.getCity());
}
if(CommonUtil.isNull(second.getDistrict())) {
second.setDistrict(first.getDistrict());
}
if(CommonUtil.isNull(second.getAddress())) {
second.setAddress(first.getAddress());
}
........
You can write this method in your data classes and do null control of all fields with one line of code. My code advice is like below:
public boolean copyIfNull(Object o)
{
Class<?> clazz = this.getClass();
Field[] fields = clazz.getDeclaredFields();
for(Field field : fields)
{
try {
Object fieldValue = field.get(this);
if (fieldValue == null)
{
field.set(this, field.get(o));
return false;
}
}
catch (Exception e) {
System.err.println("Field value could not be obtained");
e.printStackTrace();
return false;
}
}
return true;
}
And you will call this method in main like that:
second.copyIfNull(first)
As your objects look like beans from afar, you might have a look at java.beans.Introspector and BeanInfo.
Roughly along the lines of:
BeanInfo bi = Introspector.getBeanInfo(MyObjectClass.class);
for(PropertyDescriptor p : bi.getPropertyDescriptors()) {
// perform null-check
// invoke read on source object via read method delivered by p.getReadMethod()
// write to target via method delivered by p.getWriteMethod()
}
Say I have the following code...
#FunctionalInterface
static interface MessageFunction<T> {
void send(T obj);
}
static #interface Message {
Class<?> value();
}
static class Foo {
#Message(String.class)
MessageFunction<String> bass = (string) -> {
// Do Stuff
};
}
static class MessageManager {
Map<Class<?>, MessageFunction<?>> messages = new HashMap<>();
public void register(Object obj) {
for (Field field : obj.getClass().getDeclaredFields()) {
Message message = field.getAnnotation(Message.class);
if (message != null) {
MessageFunction<?> function;
try {
function = (MessageFunction<?>) field.get(obj);
} catch (IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
return;
}
Method sendMethod;
try {
// Will this work?
sendMethod = function.getClass().getDeclaredMethod("send", Object.class);
} catch (NoSuchMethodException | SecurityException e) {
e.printStackTrace();
return;
}
// How do I do something like this?
/*if (sendMethod.testParamaters(message.value())) {
this.messages.put(message.value(), function);
}*/
}
}
}
}
public static void main(String[] args) {
MessageManager manager = new MessageManager();
manager.register(new Foo());
}
I am reflecting a field that references an #FunctionalInterface of a generic type. Because the method parameter is also generic I have no way of knowing what parameters it accepts, Thus I must pass it along through other means (the annotation).
The issue is that there is the annotation value and the generic type do not have to match and there seems to be no way to check. I wan't it to fail in registration if the type listed in the annotation would not be accepted into the send method.
How would I go about thing this without actually calling the method. Is there a way? Better yet although I know its most likely impossible, is there a way to know what the parameter type is without the annotation?
The following is just a suggestion, I have used it in my project. But it is not a perfect solution for the question. May be you can download the source of GenericHibernateDao framework and see the sourcecode of method "getTypeArguments". I think it is so cool!.
// get a class object for your entity
Class clazz = ...
Type type = clazz.getGenericSuperclass();
if (type instanceof ParameterizedType) {
Type trueType = ((ParameterizedType)type).getActualTypeArguments()[0];
Class modelClass = (Class) trueType;
// Now you can creat an Instance in you generic parameterType
Object entity = modelClass.forInstance();
}
I do something similar in some of my code Here is a snippet.
Method[] meths = actionClass.getMethods();
for (Method meth : meths) {
Class<?>[] pTypes = meth.getParameterTypes();
/*
* Filter out all methods that do not meet correct
* signature. The correct signature for an action method
* is: String actionName(HttpServletRequest request)
*/
//...check for the correct number of params and the correct param type
if (pTypes.length != 1 || !HttpServletRequest.class.toString().equals(pTypes[0].toString())) {
continue;
} else {
//...check for return type
if (!String.class.toString().equals(meth.getReturnType().toString())) {
continue;
}
}
//If you make it here than that means the method
//meets the requirements to be a full fledged action.
//...
}
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).
The idea is to have a POJO like:
class MyBean {
long id;
int count;
public void setCount(int count){
this.count = count;
}
}
Now, I need that the count be stored automatically as:
put("count", count);
or simply put, put("fieldname", fieldvalue);
Is there a library that can be used for this purpose that MyBean can exetnd to? I can easily do a copy constructor or something, however, the point here is automation and besides there are so many models in my app that will be having this Map stored POJO values...
You could create a simple PropertyMapGenerator using Apache Commons BeanUtils' PropertyUtils
public class PropertyMapGenerator {
public static Map<String, Object> getPropertyMap(Object object) {
HashMap<String, Object> propertyMap = new HashMap<>();
// retrieve descriptors for all properties
PropertyDescriptor[] descriptors = PropertyUtils.getPropertyDescriptors(object);
for (PropertyDescriptor descriptor : descriptors) {
// check if there is a reader method for this property i.e. if it can be accessed
if (descriptor.getReadMethod() != null) {
String name = descriptor.getName();
try {
propertyMap.put(name, PropertyUtils.getProperty(object, name));
} catch (Exception e) {
// handle this properly
e.printStackTrace();
}
}
}
return propertyMap;
}
}
Now you can simply pass your POJOs to this generator:
Map<String, Object> propertyMap = PropertyMapGenerator.getPropertyMap(myBean);