Raghu Venmarathoor
Raghu Venmarathoor

Reputation: 868

Identify the property by passing @JsonProperty value to object mapper

I am using spring and hibernate. I have a class (DTO) with a lot of string member variables. I'm trying to implement search for this class. The user should be able to search by each field. I'm using jackson json mapper to serialize and deserialize objects. Is there anyway to identify the fieldName by using JsonProperty value?

Let this be an example: my DTO

public class SampleDTO{
  private String field1;
  private String field2;
  private String field3;
  private String field4;
  @JsonProperty("FIELD_1")
  public String getField1(){
    return field1;
  }
  @JsonProperty("FIELD_2")
  public String getField2(){
    return field2;
  }
  @JsonProperty("FIELD_3")
  public String getField3(){
    return field3;
  }
  @JsonProperty("FIELD_4")
  public String getField4(){
    return field4;
  }
}

Let this be my search function

public Set<T> search(String fieldName, String searchKeyword) {
   String originalFieldName = someMagicFunction(fieldName);
   //if fieldName= "FIELD_1", someMagicFunction should return "field1"
   Criteria criteria = session.createCriteria(T.class);
   criteria.add(Restrictions.eq(originalFieldName, searchKeyword));
   return new HashSet<T>(criteria.list());
} 

Any implementation is fine. I'm looking for a good approach to handle cases like this. It feels like finding fields manually involves "too much typing".

Upvotes: 2

Views: 10875

Answers (2)

Raghu Venmarathoor
Raghu Venmarathoor

Reputation: 868

In case if anyone is interested, this is how I solved the problem. I added this code to DAO's constructor.

try {

  BeanInfo beanInfo = Introspector.getBeanInfo(T.class);
  Method[] methods = T.class.getMethods();
  PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
  for(PropertyDescriptor propertyDescriptor: propertyDescriptors) {
    //I'm looking for string fields only
   if (propertyDescriptor.getPropertyType().equals( String.class)) {
   //My annotations are on methods
    for(Method method: methods) {
    if(propertyDescriptor.getReadMethod().equals(method)) {
      JsonProperty jsonProperty = method.getAnnotation(JsonProperty.class);
      if (jsonProperty != null) {
        //jsonFieldMapping is a Map<String,String> 
        //will be saving the mapping in the format {"FIELD_1":"field1", "FIELD_2":"field2"}
        jsonFieldMapping.put(jsonProperty.value(), propertyDescriptor.getDisplayName());
      } else {
        logger.debug("jsonProperty is null");
      }
    }
  }
}
  }
  // just printing out the values identified from class
  for(String key: jsonFieldMapping.keySet()) {
logger.debug("key: " + key + "value: " + jsonFieldMapping.get(key));

  }
} catch (IntrospectionException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
}

So, my magic method will be

public String getField(String jsonFieldName){
  if (jsonFieldMapping.containsKey(jsonFieldName)) {
      return jsonFieldMapping.get(jsonFieldName);
    } else {
      throw new IllegalArgumentException("searching field not found");
    }
}

I haven't tested this code completely. Looks like the values in the logs are correct.

Upvotes: 1

Rafal G.
Rafal G.

Reputation: 4432

You basically want to use reflection. There are two possibilities here when it comes to field lookup:

  • Value of @JsonProperty annotation
  • Real name of the field

In the first case you may want to use some additional library to ease the pain when using reflection + annotation, but the crude code would look more less like this:

    SampleDTO dto = new SampleDTO();
    // setup some values here

    Field[] fields = r.getClass().getFields();

    for(Field f : fields) {
        JsonProperty jsonProperty = f.getDeclaredAnnotation(JsonProperty.class);

        if (jsonProperty != null && jsonProperty.value().equals("FIELD_1")) {
            return (String) f.get(dto);
        }

        // throw exception since passed field name is illegal
     }        

In the second one it would be so much easier:

    SampleDTO dto = new SampleDTO();
    // setup some values here

    String field1Value = (String) r.getClass().getField("field1").get(dto);

Upvotes: 5

Related Questions