В поисках объяснения этого любопытного поведения во время де / сериализации перечислений

Недавно я столкнулся с любопытным поведением при де / сериализации перечислений в / из 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());
Другие вопросы по тегам