Created
April 20, 2019 16:08
-
-
Save liemle3893/8938397bd203d730738d1e93f952a320 to your computer and use it in GitHub Desktop.
Parse Object into Map and vice versa (Only support primitive types)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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