2017-08-06 60 views
0

一起工作我正在創建Java應用程序,它將允許將對象存儲在數據庫中。我想要做的是通用實現,所以它可以加載json並從中創建java類。這是一個代碼應該看起來像:Java與.class

SomeClass someObject= data.getValue(SomeClass.class); 

可以說,數據將是一個json對象。我應該如何實施getValue()方法,以便我可以從中創建課程。我不希望SomeClass擴展除Object以外的任何東西。我認爲這應該使用泛型類來完成,但到目前爲止,我還沒有像這樣使用泛型類。你能指出一個關於如何實現這一點的最佳方法嗎?示例代碼將是最好的。

非常感謝

+2

您可以使用泛型來獲得泛型返回類型,但是您必須使用反射類來創建實例並通過反射來填充它。 – davidxxx

+0

直到現在還沒有聽說過他們。肯定會看一下這個,謝謝 – horin

+1

恩。您也可以直接使用提供此功能的gson或Jackson lib。 – davidxxx

回答

1

您可以諮詢傑克遜庫的源代碼,並觀察內部(或調試)的方法BeanDeserializer#vanillaDeserialize(),那裏你會發現它通過遍歷所有JSON令牌環,找到對應的字段和套他們的價值。

作爲概念證明,我已經提取的邏輯的一部分從Jacskson和包裹它內部的幼稚(和脆弱)對象映射器和幼稚(和脆弱)JSON解析器:

public static class NaiveObjectMapper { 
    private Map<String, Object> fieldsAndMethods; 
    private NaiveJsonParser parser; 

    public <T> T readValue(String content, Class<T> valueType) { 
    parser = new NaiveJsonParser(content); 

    try { 
     // aggregate all value type fields and methods inside a map 
    fieldsAndMethods = new HashMap<>(); 
     for (Field field : valueType.getDeclaredFields()) { 
     fieldsAndMethods.put(field.getName(), field); 
     } 
     for (Method method : valueType.getMethods()) { 
     fieldsAndMethods.put(method.getName(), method); 
     } 

     // create an instance of value type by calling its default constructor 
     Constructor<T> constructor = valueType.getConstructor(); 
    Object bean = constructor.newInstance(new Object[0]); 

     // loop through all json nodes 
     String propName; 
     while ((propName = parser.nextFieldName()) != null) { 
     // find the corresponding field 
     Field prop = (Field) fieldsAndMethods.get(propName); 
     // get and set field value 
     deserializeAndSet(prop, bean); 
     } 
     return (T) bean; 
    } catch (NoSuchMethodException e) { 
     e.printStackTrace(); 
    } catch (IllegalAccessException e) { 
    e.printStackTrace(); 
    } catch (InstantiationException e) { 
     e.printStackTrace(); 
    } catch (InvocationTargetException e) { 
     e.printStackTrace(); 
    } 

    return null; 
    } 

    private void deserializeAndSet(Field prop, Object bean) { 
    Class<?> propType = prop.getType(); 
    Method setter = (Method) fieldsAndMethods.get(getFieldSetterName(prop)); 
    try { 
     if (propType.isPrimitive()) { 
     if (propType.getName().equals("int")) { 
      setter.invoke(bean, parser.getIntValue()); 
     } 
     } else if (propType == String.class) { 
     setter.invoke(bean, parser.getTextValue()); 
     } 
    } catch (IllegalAccessException e) { 
     e.printStackTrace(); 
    } catch (InvocationTargetException e) { 
     e.printStackTrace(); 
    } 
    } 

    private String getFieldSetterName(Field prop) { 
    String propName = prop.getName(); 
    return "set" + propName.substring(0, 1).toUpperCase() + propName.substring(1); 
    } 
} 

class NaiveJsonParser { 
    String[] nodes; 
    int currentNodeIdx = -1; 
    String currentProperty; 
    String currentValueStr; 

    public NaiveJsonParser(String content) { 
    // split the content into 'property:value' nodes 
    nodes = content.replaceAll("[{}]", "").split(","); 
} 

    public String nextFieldName() { 
    if ((++currentNodeIdx) >= nodes.length) { 
     return null; 
    } 
    String[] propertyAndValue = nodes[currentNodeIdx].split(":"); 
    currentProperty = propertyAndValue[0].replace("\"", "").trim(); 
    currentValueStr = propertyAndValue[1].replace("\"", "").trim(); 
    return currentProperty; 
    } 

    public String getTextValue() { 
    return String.valueOf(currentValueStr); 
    } 

    public int getIntValue() { 
    return Integer.valueOf(currentValueStr).intValue(); 
    } 
} 

public static class User { 
    private int id; 
    private String name; 

    public int getId() { 
    return id; 
    } 

    public void setId(int id) { 
    this.id = id; 
    } 

    public String getName() { 
    return name; 
    } 

    public void setName(String name) { 
    this.name = name; 
    } 

    @Override 
    public String toString() { 
    return "id = " + id + ", name = \"" + name + "\""; 
    } 
} 

要看到反序列化在行動中運行:

String json = "{\"id\":1, \"name\":\"jsmith\"}"; 
NaiveObjectMapper objectMapper = new NaiveObjectMapper(); 
User user = objectMapper.readValue(json, User.class); 
System.out.println(user); 

或嘗試online

但是,我建議不要重新發明輪子並使用Jackson,如果您需要某些自定義操作,則可以使用自定義反序列化,請參閱herehere