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.
MultipleType
Surtout 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