Skip to content

Instantly share code, notes, and snippets.

@liemle3893
Created April 20, 2019 16:08
Show Gist options
  • Save liemle3893/8938397bd203d730738d1e93f952a320 to your computer and use it in GitHub Desktop.
Save liemle3893/8938397bd203d730738d1e93f952a320 to your computer and use it in GitHub Desktop.
Parse Object into Map and vice versa (Only support primitive types)
import com.google.common.base.Strings;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import lombok.extern.slf4j.Slf4j;
import wpl.streaming.consumer.stream.util.reflect.annotation.Ignore;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Read object into Map<String, String>
*
* @author liemlhd
*/
@Slf4j
public final class ObjectReader {
private ObjectReader() {
throw new UnsupportedOperationException();
}
public static <T> T parse(Map<String, String> map, Class<T> clazz) {
try {
T instance = clazz.newInstance();
Field[] fields = clazz.getDeclaredFields();
for (Field f : fields) {
f.setAccessible(true);
String fieldName = f.getName();
Class<?> fieldType = f.getType();
if (isPrimitiveType(fieldType)) {
try {
Object fieldValue = extractValue(map.get(fieldName), fieldType);
if (fieldValue != null) {
f.set(instance, fieldValue);
}
} catch (Exception ex) {
log.error("Fail to set field value. {}", fieldName, ex);
}
} else {
Map<String, String> fieldValueMap = new HashMap<>();
Iterator<Map.Entry<String, String>> ite = map.entrySet().iterator();
for (; ite.hasNext();) {
Map.Entry<String, String> e = ite.next();
String fieldPrefix = fieldName + ".";
if (e.getKey().startsWith(fieldPrefix)) {
String newKey = e.getKey().substring(fieldPrefix.length());
fieldValueMap.put(newKey, e.getValue());
ite.remove();
}
}
try {
Object fieldValue = parse(fieldValueMap, fieldType);
f.set(instance, fieldValue);
} catch (Exception ex) {
log.error("Fail to set field value. {}", fieldName, ex);
}
}
}
return instance;
} catch (Exception ex) {
log.error("Fail to parse object.", ex);
return null;
}
}
public static Map<String, String> read(Object obj) {
return read("", obj);
}
private static Map<String, String> read(String prefix, Object obj) {
if (obj == null || isPrimitive(obj)) {
return Collections.emptyMap();
}
Map<String, String> result = new HashMap<>();
Class<?> clazz = obj.getClass();
for (Field f : clazz.getDeclaredFields()) {
Ignore ignore = f.getAnnotation(Ignore.class);
if (ignore != null) {
continue;
}
f.setAccessible(true);
try {
Object value = f.get(obj);
String fieldName = f.getName();
fieldName = Strings.isNullOrEmpty(prefix) ? fieldName : prefix + "." + fieldName;
if (isPrimitive(value)) {
result.put(fieldName, String.valueOf(value));
} else {
Map<String, String> nestedObject = read(fieldName, value);
result.putAll(nestedObject);
}
} catch (Exception ex) {
log.error("Failed", ex);
}
}
return result;
}
private static boolean isPrimitive(Object obj) {
return obj.getClass().isPrimitive()
|| isWrapperType(obj.getClass())
// String/Charsequence is primitive as well
|| CharSequence.class.isInstance(obj);
}
public static boolean isPrimitiveType(Class<?> type) {
return isWrapperType(type) || type.isPrimitive() || CharSequence.class.isAssignableFrom(type);
}
private static final Set<Class<?>> WRAPPER_TYPES = getWrapperTypes();
private static boolean isWrapperType(Class<?> clazz) {
return WRAPPER_TYPES.contains(clazz);
}
private static Set<Class<?>> getWrapperTypes() {
Set<Class<?>> ret = new HashSet<Class<?>>();
ret.add(Boolean.class);
ret.add(Character.class);
ret.add(Byte.class);
ret.add(Short.class);
ret.add(Integer.class);
ret.add(Long.class);
ret.add(Float.class);
ret.add(Double.class);
ret.add(Void.class);
return ret;
}
static Object extractValue(String value, Class<?> type) {
if (CharSequence.class.isAssignableFrom(type)) {
return (value);
} else if (Boolean.class.isAssignableFrom(type)
|| boolean.class.isAssignableFrom(type)) {
return Boolean.valueOf((value));
} else if (Byte.class.isAssignableFrom(type)
|| byte.class.isAssignableFrom(type)) {
return Byte.valueOf((value));
} else if (Short.class.isAssignableFrom(type)
|| short.class.isAssignableFrom(type)) {
return Short.valueOf((value));
} else if (Integer.class.isAssignableFrom(type)
|| int.class.isAssignableFrom(type)) {
return Integer.valueOf((value));
} else if (Long.class.isAssignableFrom(type)
|| long.class.isAssignableFrom(type)) {
return Long.valueOf(String.valueOf(value));
} else if (Float.class.isAssignableFrom(type)
|| float.class.isAssignableFrom(type)) {
return Float.valueOf((value));
} else if (Double.class.isAssignableFrom(type)
|| double.class.isAssignableFrom(type)) {
return Double.valueOf((value));
} else {
throw new IllegalArgumentException("Unsupported type: " + type.getName());
}
}
}
/**
*
* @author liemlhd
*/
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = {ElementType.FIELD})
@interface Ignore {
}
// Test
@Test
public void test() throws Exception {
A a = new A();
a.d = 5;
a.e = "7";
B testClass = new B();
testClass.a = 1;
testClass.b = "2";
testClass.c = 3.0;
testClass.x = a;
Map<String, String> result = ObjectReader.read(testClass);
System.out.println("result = " + result);
Map<String, String> expected = new HashMap<>();
expected.put("a", "1");
expected.put("b", "2");
expected.put("c", "3.0");
expected.put("x.d", "5");
expected.put("x.e", "7");
assertEquals(expected, result);
//
B b = ObjectReader.parse(expected, B.class);
assertEquals(b, testClass);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment