在 de-/serialization 个枚举期间寻找对这种奇怪行为的解释
Looking for an explanation of this curious behaviour during de-/serialization of enums
最近我在 de-/serialization 枚举 to/from JSON 期间遇到了一个奇怪的行为。
我将相关部分简化为一个简单的示例(请参见下面的代码)。基本上你有一个包含枚举条目的列表。您序列化列表,然后反序列化它。如果您检查新的(反序列化的)列表是否包含某些枚举条目,您将始终得到 'false' 作为答案,即使该列表实际上包含该条目。
自己稍微分析了一下,发现list反序列化后,内容不再是枚举类型,而是包含字符串。
我想了解为什么会发生这种情况以及如何避免这种情况。我的目标是在反序列化后再次获得枚举条目列表,而不是字符串列表。
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import javax.json.bind.JsonbBuilder;
import javax.json.bind.JsonbConfig;
public class Test {
enum TYPE {
SMALL, MEDIUM, LARGE
}
public static void main(String[] args) {
List<TYPE> myList = new ArrayList<>();
myList.add( TYPE.MEDIUM );
// serialize
String serializedJsonString = JsonbBuilder.create(new JsonbConfig().withLocale(Locale.GERMAN).withFormatting(true)).toJson(myList);
// deserialize
@SuppressWarnings("unchecked")
List<TYPE> mySecondList = JsonbBuilder.create(new JsonbConfig().withLocale(Locale.GERMAN).withFormatting(true)).fromJson(serializedJsonString, List.class);
System.out.println( myList.contains( TYPE.MEDIUM ) ); // will be true (as expected)
System.out.println( mySecondList.contains( TYPE.MEDIUM ) ); // will be false (surprising!)
System.out.println( mySecondList.contains( "MEDIUM" ) ); // will be true (surprising!)
}
}
Java 枚举默认序列化为字符串,因为没有更好的默认 JSON 类型。 (如果您愿意,可以将它们配置为序列化为整数。)
当你反序列化时,你必须指示Jsonb解析器将JSON个字符串转换为枚举,否则它会默认将它们反序列化为Java个字符串。
您在上面的示例中没有这样做,因为您要求它提供 List.class
(即 List<?>
),而不是 TYPE
枚举列表(List<TYPE>
).由于类型擦除,这在 Java 中很难做到。 (请注意,您必须将代码标记为 "unchecked",因为编译器知道您的版本不起作用。)JsonB 文档明确讨论了这种情况:http://json-b.net/docs/user-guide.html#mapping-a-generic-collection
试试这样的:
List<TYPE> mySecondList = jsonb.fromJson(result, new ArrayList<TYPE>(){}.getClass().getGenericSuperclass());
最近我在 de-/serialization 枚举 to/from JSON 期间遇到了一个奇怪的行为。
我将相关部分简化为一个简单的示例(请参见下面的代码)。基本上你有一个包含枚举条目的列表。您序列化列表,然后反序列化它。如果您检查新的(反序列化的)列表是否包含某些枚举条目,您将始终得到 'false' 作为答案,即使该列表实际上包含该条目。
自己稍微分析了一下,发现list反序列化后,内容不再是枚举类型,而是包含字符串。
我想了解为什么会发生这种情况以及如何避免这种情况。我的目标是在反序列化后再次获得枚举条目列表,而不是字符串列表。
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import javax.json.bind.JsonbBuilder;
import javax.json.bind.JsonbConfig;
public class Test {
enum TYPE {
SMALL, MEDIUM, LARGE
}
public static void main(String[] args) {
List<TYPE> myList = new ArrayList<>();
myList.add( TYPE.MEDIUM );
// serialize
String serializedJsonString = JsonbBuilder.create(new JsonbConfig().withLocale(Locale.GERMAN).withFormatting(true)).toJson(myList);
// deserialize
@SuppressWarnings("unchecked")
List<TYPE> mySecondList = JsonbBuilder.create(new JsonbConfig().withLocale(Locale.GERMAN).withFormatting(true)).fromJson(serializedJsonString, List.class);
System.out.println( myList.contains( TYPE.MEDIUM ) ); // will be true (as expected)
System.out.println( mySecondList.contains( TYPE.MEDIUM ) ); // will be false (surprising!)
System.out.println( mySecondList.contains( "MEDIUM" ) ); // will be true (surprising!)
}
}
Java 枚举默认序列化为字符串,因为没有更好的默认 JSON 类型。 (如果您愿意,可以将它们配置为序列化为整数。)
当你反序列化时,你必须指示Jsonb解析器将JSON个字符串转换为枚举,否则它会默认将它们反序列化为Java个字符串。
您在上面的示例中没有这样做,因为您要求它提供 List.class
(即 List<?>
),而不是 TYPE
枚举列表(List<TYPE>
).由于类型擦除,这在 Java 中很难做到。 (请注意,您必须将代码标记为 "unchecked",因为编译器知道您的版本不起作用。)JsonB 文档明确讨论了这种情况:http://json-b.net/docs/user-guide.html#mapping-a-generic-collection
试试这样的:
List<TYPE> mySecondList = jsonb.fromJson(result, new ArrayList<TYPE>(){}.getClass().getGenericSuperclass());