Страницы

Поиск по вопросам

среда, 11 декабря 2019 г.

Как указать Gson`у, чтобы он использовал именно мой сериализатор/десериализатор?

#java #json #gson


Написал собственный конвертер, зарегистрировал в GsonBuilder'е. Но отрабатывает только
сериализатор и только в одном "rest-методе". 

То есть, он работает, но работает сериализация и десериализация по умолчанию, а мой
конвертер работает только при сериализации одного метода, когда получаю список объектов,
в остальных случаях игнорируется. В логах ошибок нет, тихо и не правильно работает,
не знаю уже что делать. Сталкивался ли кто-нибудь с таким, что не так идет?

Наверно это лишнее, но всё же распишу подробнее.

Провайдер для gson'а.

Класс GsonJsonProvider.java

@Provider
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class GsonJsonProvider implements MessageBodyReader, MessageBodyWriter{

//---
//инициализация gson и его настроек
private Gson getGson(){
    if (gson == null) {
        gson = new GsonBuilder()
                .registerTypeAdapter(UUID.class, new UUIDConverter())
                .registerTypeAdapter(LocalDateTime.class, new DateTimeConverter())
                .registerTypeAdapter(Note.class, new NoteConverter())
                .setPrettyPrinting()
                .serializeNulls()
                .setLenient()
                .create();

        System.err.println("Gson Initialization");
    }
    System.err.println("Gson work");
    return gson;
}
//---
//метод getGson вызывается в этих методах и больше нигде
public Object readFrom(Class type, Type genericType, Annotation[] annotations,
MediaType mediaType, MultivaluedMap httpHeaders, InputStream entityStream)
throws IOException, WebApplicationException {
    InputStreamReader streamReader = new InputStreamReader(entityStream, UTF_8);
    try {
        Type jsonType;
        if (type.equals(genericType)) {
            jsonType = type;
        } else {
            jsonType = genericType;
        }
        return getGson().fromJson(streamReader, jsonType);
    } finally {
        streamReader.close();
    }
}

//----
public void writeTo(Object object, Class type, Type genericType, Annotation[]
annotations, MediaType mediaType, MultivaluedMap httpHeaders, OutputStream
entityStream) throws IOException, WebApplicationException {
    OutputStreamWriter writer = new OutputStreamWriter(entityStream, UTF_8);
    try {
        Type jsonType;
        if (type.equals(genericType)) {
            jsonType = type;
        } else {
            jsonType = genericType;
        }
        getGson().toJson(object, jsonType, writer);
    } finally {
        writer.close();
    }
}


Класс модель Note.java

@Entity
@Table(name = "notes")
@NamedQuery(name = "Note.getAll", query = "SELECT n FROM Note n ORDER BY n.id ASC")
public class Note extends Model{

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id_post")
private int id;
@Type(type = "org.hibernate.type.PostgresUUIDType")
private UUID uuid;
private String title;
private String text;
private String password;
private LocalDateTime date;
private int status;
//---


Класс конвертер NoteConverter.java

@Override
public JsonElement serialize(Note note, Type type, JsonSerializationContext context) {

    JsonObject result = new JsonObject();
    result.add("uuid", context.serialize(note.getUuid()));
    result.addProperty("title", note.getTitle());
    result.addProperty("text", note.getText());
    result.addProperty("password", note.getPassword() != null ? note.getPassword()
: "null_password");
    result.add("date", context.serialize(note.getDate()));
    result.addProperty("status", note.getStatus());

    return result;
}


и

@Override
public Note deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext
context) throws JsonParseException {

    JsonObject jsonObject = jsonElement.getAsJsonObject();

    Note note = new Note();
    note.setUuid(context.deserialize(jsonObject.get("uuid"), UUID.class));
    note.setTitle(jsonObject.get("title").getAsString());
    note.setText(jsonObject.get("text").getAsString());
    note.setPassword(jsonObject.get("password").getAsString());
    note.setDate(context.deserialize(jsonObject.get("date"), LocalDateTime.class));
    note.setStatus(jsonObject.get("status").getAsInt());

    return note;
}


Класс NoteResource.java

//вот здесь мой сериализатор отрабатывает, 
//отдаёт список объектов, где поле date в миллисекундах.
//в логах светится "Gson work" тот, что в GsonJsonProvider.java 
@GET
@Produces("application/json; charset=UTF-8")
public Response getAll(){
    List noteList = dao.getAll("Note.getAll", noteClass);
    return Response.ok(noteList).build();
}

//а здесь, работает сериализация по умолчанию
//и в логах "Gson work" не выходит, то есть он вообще не при делах, почему???
@GET
@Path("/{id}")
@Produces("application/json; charset=UTF-8")
public Response getNote(@PathParam("id") int id){
    Note note = dao.getById(id, noteClass);
    return Response.ok(note).build();
}

//и здесь тоже самое, сам объект note приходит
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response addNote(Note note){
    StatusResponse response = new StatusResponse();
    if (note == null) { //эту проверку проходит
        System.err.println("Added, note null!");
        return Response.status(Response.Status.BAD_REQUEST).entity(response).build();
    }
    System.err.println("Added, note title: " + note.getTitle());
    System.err.println("Added, uuid: " + note.getUuid());
//а здесь uuid = null, так как не знает как десериализовывать тип UUID
//------


UPDATE

Добавил параметризацию в класс GsonJsonProvider.java

public class GsonJsonProvider implements MessageBodyReader, MessageBodyWriter {
//...


Метод readFrom

public T readFrom(Class type, Type genericType, Annotation[] annotations, MediaType
mediaType, MultivaluedMap httpHeaders, InputStream entityStream) throws
IOException, WebApplicationException {
    InputStreamReader streamReader = new InputStreamReader(entityStream, UTF_8);
    try {
        //с genericType так же не работает
        return getGson().fromJson(streamReader, type);
    } finally {
        streamReader.close();
    }
}


Метод writeTo

public void writeTo(T t, Class type, Type genericType, Annotation[] annotations,
MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream)
throws IOException, WebApplicationException {
    OutputStreamWriter writer = new OutputStreamWriter(entityStream, UTF_8);
    try {
        //если указывать type вместо genericType, то не работает
        getGson().toJson(t, genericType, writer);
    } finally {
        writer.close();
    }
}

//Сериализация работает как надо, только
//если изменить сеттер в модели Note.java
//но тогда вылетает ошибка при десериализации
//java.lang.ClassCastException: java.util.UUID cannot be cast to java.lang.String
public void setUuid(String uuidString) {
    this.uuid = UUID.fromString(uuidString);
}

//а с таким(нормальным) сеттером
//и сер/десериализация не работает (без ошибок в логах)
public void setUuid(UUID uuid) {
    this.uuid = uuid;
}

    


Ответы

Ответ 1



У вас проблема в куске: if (type.equals(genericType)) { jsonType = type; } else { jsonType = genericType; } У вас на выходе тип всегда будет genericType, то есть адаптер никогда не вызовется, поскольку вы всегда вызываете Gson с дженерик типом.

Комментариев нет:

Отправить комментарий