Реализация конечной точки PATCH с JAX-RS и Liferay (Apache CXF) - PullRequest
0 голосов
/ 21 января 2020

Я пытаюсь реализовать конечную точку PATCH с JAX-RS в модуле Liferay OSGi. Конечные точки GET , POST и PUT работают нормально, но я застрял с конечной точкой PATCH . Поскольку я не знаю ничего лучшего, я пытаюсь использовать пример реализации Даана Ширена.

Мои (упрощенные) реализации, начиная с контроллера:

@Path("/resources")
public class ResourceController {

    @PATCH
    @Path("/{resourceId}")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    Response patchResource(@PathParam("resourceId") long resourceId, ObjectPatch objectPatch) {

        // Get the resource
        Resource resource = getResource(resourceId);

        // Apply the patch
        objectPatch.apply(resource);

        // Return the resource
        return Response.ok(resource).build();
    }
}

Итак, мне нужен интерфейс ObjectPatch, который я сделал точно так же, как в примере с Daan:

public interface ObjectPatch {

    <T> T apply(T target) throws ObjectPatchException;

}

Следующий шаг - реализация MessageBodyReader:

@Provider
public class PartialJsonObjectPatchReader implements MessageBodyReader<ObjectPatch> {

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    @Override
    public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {

        return ObjectPatch.class == type && MediaType.APPLICATION_JSON_TYPE.isCompatible(mediaType);
    }

    @Override
    public ObjectPatch readFrom(Class<ObjectPatch> type, Type genericType, Annotation[] annotations,
            MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
            throws IOException {

        JsonNode patch = OBJECT_MAPPER.readTree(entityStream);

        return new PartialJsonObjectPatch(OBJECT_MAPPER, patch);
    }

}

. Отличие от примера реализации заключается в том, что я добавил аннотацию @Provider. Насколько я понял, это автоматически регистрирует реализацию MessageBodyReader во время выполнения JAX-RS, как это описано здесь и здесь . Из последнего:

Класс, желающий предоставить такой сервис, реализует интерфейс MessageBodyReader и может быть аннотирован @Provider для автоматического обнаружения c.

Я просто создается впечатление, что этого автоматического c обнаружения не происходит.

Последний важный класс - это реализация интерфейса ObjectPatch:

public class PartialJsonObjectPatch implements ObjectPatch {

    private final ObjectMapper objectMapper;
    private final JsonNode patch;

    public PartialJsonObjectPatch(ObjectMapper objectMapper, JsonNode patch) {

        this.objectMapper = objectMapper;
        this.patch = patch;
    }

    @Override
    public <T> T apply(T target) throws ObjectPatchException {

        ObjectReader reader = objectMapper.readerForUpdating(target);

        try {
            return reader.readValue(patch);
        } catch (IOException e) {
            throw new ObjectPatchException(e);
        }
    }

}

Если я сейчас сделаю PATCH запрос к конечной точке, он выдает мне следующее сообщение об ошибке:

com.faster xml .jackson.databind.ex c .InvalidDefinitionException: Невозможно создать экземпляр com.example.ObjectPatch (никаких создателей, как конструкция по умолчанию, не существует): абстрактные типы либо должны быть сопоставлены с конкретными типами, либо иметь собственный десериализатор, либо содержать дополнительную информацию о типах

Я как бы понимаю сообщение об ошибке как интерфейс не может быть создан, но я не понимаю, почему я получаю это сообщение. Не следует ли попытаться создать экземпляр PartialJsonObjectPatch вместо ObjectPatch? Если я изменю класс параметров метода patchResource() на PartialJsonObjectPatch (чего я не должен), я получу это сообщение об ошибке:

com.faster xml .jackson.databind. ex c .InvalidDefinitionException: Невозможно создать экземпляр com.example.PartialJsonObjectPatch (не существует создателей, как конструкция по умолчанию): невозможно десериализовать из значения объекта (без создателя на основе делегатов или свойств)

The сообщения об ошибках приводят меня к this , но добавление конструктора по умолчанию не помогает.

Чего мне не хватает?

1 Ответ

0 голосов
/ 23 января 2020

Аннотация @Provider недостаточна, мне пришлось добавить мою реализацию MessageBodyReader к синглетам в классе Application:

    @Override
    public Set<Object> getSingletons() {

        Set<Object> singletons = new HashSet<>();

        // All your other Providers, Readers, Writers, e.g:
        singletons.add(new JacksonJaxbJsonProvider());

        // My MessageBodyReader implementation
        singletons.add(new PartialJsonObjectPatchReader());

        return singletons;
    }
...