Lorsque j'ai obtenu le JSON avec l'API REST Redmine, la notation suivante est apparue dans "custom_fields".
"custom_fields": [
{
"id": 1,
"name": "Objet 1",
"value": "a"
},
{
"id": 2,
"name": "Point 2",
"multiple": true,
"value": [
"b"
]
},
{
"id": 3,
"name": "Point 3",
"multiple": true,
"value": [
"c",
"d"
]
},
Il semble que si le contenu de «valeur» est «multiple»: vrai », c'est un objet tableau, sinon il est unique. Comme dans l'exemple ci-dessus, il existe 3 modèles.
Il existe aussi une méthode pour tout convertir en tableau même s'il est unique au moment de la désérialisation (JSON → Java), mais comme il ne peut pas être restauré à l'expression d'origine au moment de la sérialisation (je ne sais pas s'il s'agit d'un seul ou d'un tableau avec 1 élément), mettez ce contrôle Dans cet esprit, j'ai également envisagé une mise en œuvre à usage général.
Les objets pour mettre des données au moment de la désérialisation sont les suivants.
public class MultipleType<T> {
private T value;
private List<T> values;
public boolean isMultiple() {
return values != null;
}
//Ci-dessous getter/setter
}
Utilisez une valeur ou des valeurs et rendez l'autre null.
Le "custom_fields" ci-dessus ressemble à ce qui suit.
public class CustomField {
private String id;
private String name;
private boolean multiple;
private MultipleType<String> value;
//Ci-dessous getter/setter
}
Je veux utiliser les fonctions de GSON autant que possible, donc j'utiliserai le même nom de champ que JSON.
Implémentez le sérialiseur / désérialiseur personnalisé de GSON comme suit.
public class MultipleTypeAdapter implements JsonDeserializer<MultipleType<?>>, JsonSerializer<MultipleType<?>> {
@Override
public MultipleType<?> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
final MultipleType<?> result = new MultipleType<>();
if (json.isJsonArray()) {
result.setValues(deserializeArray(json, typeOfT, context));
} else {
result.setValue(context.deserialize(json, getGenericType(typeOfT)));
}
return result;
}
private <T> List<T> deserializeArray(JsonElement json, Type typeOfT, JsonDeserializationContext context) {
final List<T> values = new ArrayList<>();
final Type t = getGenericType(typeOfT);
for (JsonElement e : json.getAsJsonArray()) {
values.add(context.deserialize(e, t));
}
return values;
}
/* get actual Type of <?> */
private Type getGenericType(Type typeOfT) {
return ((ParameterizedType) typeOfT).getActualTypeArguments()[0];
}
@Override
public JsonElement serialize(MultipleType<?> src, Type typeOfSrc, JsonSerializationContext context) {
return context.serialize(src.isMultiple() ? src.getValues() : src.getValue());
}
}
Il y a trois points principaux.
MultipleTypeSurtout 2 est un peu compliqué.
Tout d'abord, nous devons savoir ce que représente l'argument Type typeOfT de la méthode deserialize.
Il contient un objet qui représente le paramètre de type de l'interface JsonDeserializer.
(Pour être exact, le type de l'objet réellement utilisé lors de l'exécution)
Les paramètres de type génériques sont perdus au moment de la compilation, vous pouvez donc vous y référer au moment de l'exécution.
La définition nous dit que typeOfT est MultipleType <?>, Mais comme nous avons besoin de connaître la partie<?>, Nous obtenons les paramètres de type internes avec la méthode getGenericType. Je vais.
La raison pour laquelle le type d'exécution du paramètre de type <?> Est nécessaire est que si le type correct est donné par la méthode context.deserialize, la désérialisation ultérieure peut être laissée à la fonction de GSON. ..
En particulier, vous n'avez pas besoin d'écrire à la main une désérialisation de structure complexe où les champs de l'objet de données sont de type non primitif (y compris String).
L'utilisation de GSON est la suivante.
final GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(MultipleType.class, new MultipleTypeAdapter());
final Gson gson = gsonBuilder.create();
Puisque la classe MultipleTypeAdapter n'est pas un type générique, c'est une erreur qu'il n'y a pas d'avertissement.
C'est pourquoi nous avons utilisé <?> (Wildcards) pour les paramètres de type désérialiseur / sérialiseur personnalisé.
(Je ne peux pas expliquer pourquoi les jokers sont OK ...)
J'utilise le type générique de Java comme "générique" dans les phrases et la prononciation comme "générique". N'est-il pas difficile de dire «génériques»?
Recommended Posts