Пользовательский сериализатор и десериализатор JAX-RS для @QueryParam для конечной точки - PullRequest
0 голосов
/ 11 января 2019

У меня есть некоторые конечные точки REST, которые должны получить параметр класса SecretData, например:

@GET
@Path(/*...*/)
public someInternalService(@QueryParam("data") SecretData outLittleSecret) {/*...*/}

@GET
@Path(/*...*/)
public someExternalService(@QueryParam("opaque") SecretData outLittleSecret) {/*...*/}

Теперь, учитывая, что SecretData передает некоторую непубличную информацию, я бы хотел зашифровать ее, когда она поступает из внешнего источника (через эту конкретную конечную точку someExternalService).

Криптографическая процедура здесь не имеет значения. Дело в том, что у меня есть 2 представления для одного и того же класса данных.

У меня не может быть статических valueOf() или fromString(), реализованных в классе SecretData, потому что это повлияет и на другую конечную точку.

Как предоставить пользовательский маршаллер для класса SecretData, который применяется только для конечной точки someExternalService?

1 Ответ

0 голосов
/ 13 января 2019

Как я могу предоставить собственный маршаллер для класса SecretData, который применяется только для конечной точки someExternalService?

Ну, AFAIK, вы не можете (см. Примечание № 3). Но вы можете решить свою проблему, используя разделение интересов и создав иерархический дизайн вашего API ... позвольте мне объяснить ...

Предположим, что Data - это ваш главный объект (это будет то, что вы сейчас называете «обычным» SecretData), он содержит информацию, которую внутренние (или внешние) службы хотят передать ...

public class Data {
    protected int attribA;
    ...
    protected String attribN;

    public static Data valueOf(String data) {
        // here, you transform the string and set
        // the corresponding attributes values
    }
}

Затем вы можете определить конечную точку следующим образом:

@GET
@Path(/*...*/)
public someInternalService(@QueryParam("data") Data data) {/*...*/}

Теперь для внешних сервисов вы создаете новый POJO («разделение интересов») следующим образом:

public class EncryptedData extends Data {
    // any attribute is inherited from data
    // this class does not expose new attributes

    /**
     * Copy constructor.
     */
    EncryptedData(Data data) {
        super();
        this.attribA = data.attribA;
        ...
    };

    public static EncryptedData valueOf(String opaque) {
        // here, you transform the encrypted String into
        // a regular String, then you call Data.valueOf ...
        // example:
        String decrypted = decrypt(opaque);
        return new EncryptedData( Data.valueOf(decrypted) );
    }
}

Тогда ваша конечная точка внешних служб будет выглядеть так:

@GET
@Path(/*...*/)
public someExternalService(@QueryParam("opaque") EncryptedData data) {/*...*/}

ПРИМЕЧАНИЕ: Поскольку экземпляр EncryptedData IS_A Data, вы можете передать такой объект любому другому методу, который получает экземпляр Data в качестве входных данных! Таким образом, вам не нужно делать никаких других преобразований ...

ПРИМЕЧАНИЕ2: очевидно, если вы используете RestEasy в качестве реализации JAXRS, вы можете определить настраиваемый сериализатор String ... см. StringConverter

ПРИМЕЧАНИЕ3: проверка документации restEasy, JAX-RS 2.0 содержит способ создания собственного сериализатора ... см. ParamConverter ... Под В этой стратегии вам потребуется создать два ParamConverter (один для простого SecretData и один для непрозрачного SecretData); и фабрика ParameterConverter (реализация интерфейса ParamConverterProvider) ... если вы проверяете документы интерфейса, интерфейс предоставляет только один метод, и такой метод получает аннотации, примененные к параметру, который (де) сериализуется ... так, вы получите (я думаю) что-то вроде: @QueryParam("data") или @QueryParam("opaque"), и на основе этих значений вы можете соответственно создать ParameterConverter!

...