Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
JsonActionInterceptor
package com.klopaj.interceptor;
import com.klopaj.interceptor.meta.JsonAction;
import com.klopaj.interceptor.meta.JsonIn;
import flexjson.JSONDeserializer;
import flexjson.JSONSerializer;
import jodd.bean.BeanUtil;
import jodd.madvoc.ActionRequest;
import jodd.madvoc.interceptor.ActionInterceptor;
import jodd.servlet.ServletUtil;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class JsonActionInterceptor extends ActionInterceptor {
@Override
public Object intercept(ActionRequest actionRequest) throws Exception {
HttpServletRequest request = actionRequest.getHttpServletRequest();
Object action = actionRequest.getAction();
Method method = actionRequest.getActionConfig().getActionClassMethod();
if (method.isAnnotationPresent(JsonAction.class)) {
// if this is a json action, get all @JsonIn fields, and try to parse them from input
String jsonStringValue = ServletUtil.readRequestBody(request);
Object fieldValues = new JSONDeserializer<Object>().deserialize(jsonStringValue);
List<Field> fields = getAllDeclaredFields(action.getClass());
for (Field field : fields) {
if (field != null) {
if (field.isAnnotationPresent(JsonIn.class)) {
// This field is marked as @JsonIn meaning it should be in the content of the response
addFieldValueToObject(action, fieldValues, field);
}
}
}
}
return actionRequest.invoke();
}
private void addFieldValueToObject(Object action, Object fieldValues, Field field) throws IllegalAccessException, InstantiationException {
Class fieldType = field.getType();
if (fieldType == String.class || fieldType.isPrimitive() || Number.class.isAssignableFrom(fieldType)) {
// it's simple string, just try to get that value from json
Object fieldValue = getFieldValue(field.getName(), fieldValues);
field.setAccessible(true);
field.set(action, fieldValue);
} else if (List.class.isAssignableFrom(fieldType)) {
// Handle lists and similar
System.out.println("It's a collection");
List fieldValue = (List) getFieldValue(field.getName(), fieldValues);
if (field.getGenericType() instanceof ParameterizedType) {
ParameterizedType itemParameterizedType = (ParameterizedType) field.getGenericType();
Class itemType = (Class) itemParameterizedType.getActualTypeArguments()[0];
List result = new ArrayList();
for (Object object : fieldValue) {
if (object != null) {
System.out.println("Collection item " + object);
Object itemInstance = itemType.newInstance();
// Object is most likely HashMap
if (object instanceof Map) {
Map<String, Object> objectAsMap = (Map<String, Object>) object;
for (Field itemField : getAllDeclaredFields(itemInstance.getClass())) {
if (objectAsMap.get(itemField.getName()) != null) {
// we have that field's value
addFieldValueToObject(itemInstance, objectAsMap, itemField);
}
}
}
result.add(itemInstance);
}
}
BeanUtil.setDeclaredPropertyForced(action, field.getName(), result);
}
} else {
// Most likely this is a POJO.
Object fieldValue = getFieldValue(field.getName(), fieldValues);
// TODO: "Number.class" part is a hack cause current Entity (hibernate) Id is marked as "extends Serializable", but the value is always a number.
if (fieldValue.getClass().isPrimitive() || Number.class.isAssignableFrom(fieldValue.getClass())) {
field.setAccessible(true);
field.set(action, fieldValue);
} else {
String objectSerialized = new JSONSerializer().exclude("*.class").serialize(fieldValue);
Object fieldValueObject = new JSONDeserializer().deserialize(objectSerialized, fieldType);
field.setAccessible(true);
field.set(action, fieldValueObject);
}
}
}
private Object getFieldValue(String fieldName, Object fieldValues) {
if (fieldValues instanceof Map) {
Map mapFieldValue = (Map) fieldValues;
return mapFieldValue.get(fieldName);
}
return null;
}
/**
* Returns all declared fields (including all supper classes' fields)
*
* @param type Class object that we need to get it's declared fields
* @return List of Fields
*/
public List<Field> getAllDeclaredFields(Class<?> type) {
List<Field> result = new ArrayList<Field>();
return getAllDeclaredFields(result, type);
}
private List<Field> getAllDeclaredFields(List<Field> fields, Class<?> type) {
Collections.addAll(fields, type.getDeclaredFields());
if (type.getSuperclass() != null) {
fields = getAllDeclaredFields(fields, type.getSuperclass());
}
return fields;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.