В поисках объяснения этого любопытного поведения во время де / сериализации перечислений
Недавно я столкнулся с любопытным поведением при де / сериализации перечислений в / из JSON.
Я заглушил соответствующую часть в простой пример (см. Код ниже). в основном у вас есть список, содержащий записи enum. Вы сериализуете список, а затем десериализуете его. если вы проверите этот новый (десериализованный) список, если он содержит определенные записи перечисления, вы всегда получите "ложь" в качестве ответа, даже если список фактически содержит эту запись.
немного проанализировав его, я обнаружил, что после десериализации списка содержимое больше не относится к типу enum, а содержит строки.
Я хотел бы понять, почему это происходит и как я могу избежать этого. моей целью было бы иметь список записей enum снова после десериализации, а не список строк.
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!)
}
}
1 ответ
Перечисления Java сериализуются в строки по умолчанию, так как для них нет лучшего типа JSON по умолчанию. (Вы можете настроить их для сериализации в целые, если хотите.)
Когда вы десериализуете, вы должны указать анализатору Jsonb преобразовать строки JSON в перечисление, иначе он по умолчанию десериализует их в строки Java.
Вы не сделали этого в своем примере выше, потому что вы попросили List.class
(т.е. List<?>
), а не список TYPE
перечисления (List<TYPE>
). Это сложно сделать в Java из-за стирания типа. (Обратите внимание, что вы должны были пометить код как "непроверенный", потому что компилятор знает, что ваша версия не будет работать.) Документы JsonB подробно обсуждают этот случай: http://json-b.net/docs/user-guide.html
Попробуйте что-то вроде:
List<TYPE> mySecondList = jsonb.fromJson(result, new ArrayList<TYPE>(){}.getClass().getGenericSuperclass());