每个端点的 @QueryParam 自定义 JAX-RS 序列化器和反序列化器
Custom JAX-RS serializer and deserializer for @QueryParam per endpoint
我有一些 REST 端点必须接收 SecretData
class 的参数,例如:
@GET
@Path(/*...*/)
public someInternalService(@QueryParam("data") SecretData outLittleSecret) {/*...*/}
@GET
@Path(/*...*/)
public someExternalService(@QueryParam("opaque") SecretData outLittleSecret) {/*...*/}
现在,考虑到 SecretData
传达了一些非 public 信息,当它来自外部来源(通过特定端点 someExternalService
时,我想对其进行加密).
加密过程不是这里的重点。 关键是我对相同的 class 数据有 2 个表示。
我不能在 class SecretData
中实现静态 valueOf()
或 fromString()
,因为这也会影响另一个端点。
如何为 SecretData
class 提供仅适用于 someExternalService
端点的自定义编组器?
How can I provide a custom marshaller for the SecretData class that applies only for the someExternalService endpoint?
好吧,AFAIK,你不能(见注释 #3)。但是您可以使用 关注点分离 并创建 API 的分层设计来解决您的问题...让我解释一下...
假设 Data
是您的主对象(它将是您现在所说的 "plain" 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 ("separation of concerns"):
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!
我有一些 REST 端点必须接收 SecretData
class 的参数,例如:
@GET
@Path(/*...*/)
public someInternalService(@QueryParam("data") SecretData outLittleSecret) {/*...*/}
@GET
@Path(/*...*/)
public someExternalService(@QueryParam("opaque") SecretData outLittleSecret) {/*...*/}
现在,考虑到 SecretData
传达了一些非 public 信息,当它来自外部来源(通过特定端点 someExternalService
时,我想对其进行加密).
加密过程不是这里的重点。 关键是我对相同的 class 数据有 2 个表示。
我不能在 class SecretData
中实现静态 valueOf()
或 fromString()
,因为这也会影响另一个端点。
如何为 SecretData
class 提供仅适用于 someExternalService
端点的自定义编组器?
How can I provide a custom marshaller for the SecretData class that applies only for the someExternalService endpoint?
好吧,AFAIK,你不能(见注释 #3)。但是您可以使用 关注点分离 并创建 API 的分层设计来解决您的问题...让我解释一下...
假设 Data
是您的主对象(它将是您现在所说的 "plain" 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 ("separation of concerns"):
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!