【问题标题】:From JSON String to Java Object using javax.json使用 javax.json 从 JSON 字符串到 Java 对象
【发布时间】:2015-03-24 14:23:30
【问题描述】:

我正在使用com.google.gson.Gson API 将 JSON 字符串转换为 Java 对象:

Gson gson = new Gson();
User u = gson.fromJson(jsonString, User.class);

我想知道 javax.json api 中是否有等效的 API 来执行等效操作。 谢谢!

【问题讨论】:

  • 这是可能的,但绝对不能使用 oneliner。您将需要 Java Beans Introspector API 的帮助。这可以接受吗?
  • 是的,这是可以接受的(仅使用 JSON API 调用)。

标签: json jakarta-ee java-ee-7


【解决方案1】:

对于像 Gson 这样的 oneliner,这绝对是不可能的。 javax.json API 级别非常低。它只返回一个 JSON 对象结构,您必须自己进一步分解并映射到 javabean。

为了达到(几乎)与Gson#fromJson() 相同的效果,这里是样板代码的启动示例。一定程度上支持参数化类型和javabean。这都是标准的 Java SE API,javabeans 在java.beans API 的帮助下进行了自省。

@SuppressWarnings("unchecked")
public static <T> T fromJson(String json, Class<T> beanClass) {
    JsonValue value = Json.createReader(new StringReader(json)).read();
    return (T) decode(value, beanClass);
}

private static Object decode(JsonValue jsonValue, Type targetType) {
    if (jsonValue.getValueType() == ValueType.NULL) {
        return null;
    }
    else if (jsonValue.getValueType() == ValueType.TRUE || jsonValue.getValueType() == ValueType.FALSE) {
        return decodeBoolean(jsonValue, targetType);
    }
    else if (jsonValue instanceof JsonNumber) {
        return decodeNumber((JsonNumber) jsonValue, targetType);
    }
    else if (jsonValue instanceof JsonString) {
        return decodeString((JsonString) jsonValue, targetType);
    }
    else if (jsonValue instanceof JsonArray) {
        return decodeArray((JsonArray) jsonValue, targetType);
    }
    else if (jsonValue instanceof JsonObject) {
        return decodeObject((JsonObject) jsonValue, targetType);
    }
    else {
        throw new UnsupportedOperationException("Unsupported json value: " + jsonValue);
    }
}

private static Object decodeBoolean(JsonValue jsonValue, Type targetType) {
    if (targetType == boolean.class || targetType == Boolean.class) {
        return Boolean.valueOf(jsonValue.toString());
    }
    else {
        throw new UnsupportedOperationException("Unsupported boolean type: " + targetType);
    }
}

private static Object decodeNumber(JsonNumber jsonNumber, Type targetType) {
    if (targetType == int.class || targetType == Integer.class) {
        return jsonNumber.intValue();
    }
    else if (targetType == long.class || targetType == Long.class) {
        return jsonNumber.longValue();
    }
    else {
        throw new UnsupportedOperationException("Unsupported number type: " + targetType);
    }
}

private static Object decodeString(JsonString jsonString, Type targetType) {
    if (targetType == String.class) {
        return jsonString.getString();
    }
    else if (targetType == Date.class) {
        try {
            return new SimpleDateFormat("MMM dd, yyyy H:mm:ss a", Locale.ENGLISH).parse(jsonString.getString()); // This is default Gson format. Alter if necessary.
        }
        catch (ParseException e) {
            throw new UnsupportedOperationException("Unsupported date format: " + jsonString.getString());
        }
    }
    else {
        throw new UnsupportedOperationException("Unsupported string type: " + targetType);
    }
}

private static Object decodeArray(JsonArray jsonArray, Type targetType) {
    Class<?> targetClass = (Class<?>) ((targetType instanceof ParameterizedType) ? ((ParameterizedType) targetType).getRawType() : targetType);

    if (List.class.isAssignableFrom(targetClass)) {
        Class<?> elementClass = (Class<?>) ((ParameterizedType) targetType).getActualTypeArguments()[0];
        List<Object> list = new ArrayList<>();

        for (JsonValue item : jsonArray) {
            list.add(decode(item, elementClass));
        }

        return list;
    }
    else if (targetClass.isArray()) {
        Class<?> elementClass = targetClass.getComponentType();
        Object array = Array.newInstance(elementClass, jsonArray.size());

        for (int i = 0; i < jsonArray.size(); i++) {
            Array.set(array, i, decode(jsonArray.get(i), elementClass));
        }

        return array;
    }
    else {
        throw new UnsupportedOperationException("Unsupported array type: " + targetClass);
    }
}

private static Object decodeObject(JsonObject object, Type targetType) {
    Class<?> targetClass = (Class<?>) ((targetType instanceof ParameterizedType) ? ((ParameterizedType) targetType).getRawType() : targetType);

    if (Map.class.isAssignableFrom(targetClass)) {
        Class<?> valueClass = (Class<?>) ((ParameterizedType) targetType).getActualTypeArguments()[1];
        Map<String, Object> map = new LinkedHashMap<>();

        for (Entry<String, JsonValue> entry : object.entrySet()) {
            map.put(entry.getKey(), decode(entry.getValue(), valueClass));
        }

        return map;
    }
    else try {
        Object bean = targetClass.newInstance();

        for (PropertyDescriptor property : Introspector.getBeanInfo(targetClass).getPropertyDescriptors()) {
            if (property.getWriteMethod() != null && object.containsKey(property.getName())) {
                property.getWriteMethod().invoke(bean, decode(object.get(property.getName()), property.getWriteMethod().getGenericParameterTypes()[0]));
            }
        }

        return bean;
    }
    catch (Exception e) {
        throw new UnsupportedOperationException("Unsupported object type: " + targetClass, e);
    }
}

用法:

User u = YourJsonUtil.fromJson(jsonString, User.class);

如果您看到来自decodeXxx() 方法之一的UnsupportedOperationException,只需将所需的转换逻辑添加到相关方法即可。当然,这可以进一步重构以应用策略模式等,使其具有灵活性和可扩展性,但我们基本上是在重新发明 Gson。

【讨论】:

    【解决方案2】:

    不,没有。

    在您尝试其他解析器之前,GSON: org.json 有错误/有实现错误。 QuickJson 有问题/有实现错误

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-04
      相关资源
      最近更新 更多