我试图能够定义以下代码:
public class MyObject {
private String name;
... // Other attributes
}
@Path(...)
@Stateless
public class MyRestResource {
@POST
@Consumes(MediaType.APPLICATION_JSON)
public Response create(List<MyObject> myObjects) {
// Do some stuff there
}
}
我知道我需要使用:
DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true
要正确设置对象映射器,以便能够在rest资源上接受单个值作为数组。我成功地安装了那个部件。
我对这种方法的问题是,以下内容是不可区分的:
{
"name": "a name",
... // other attributes
}
和
[{
"name": "a name",
... // other attributes
}]
将产生一个大小为1的列表。然后,在方法create(List myObjects)中,我将无法区分List和发送到Rest资源的单个对象。
那么,我的问题是如何做到这一点。我们的想法是只有一个@POST同时接受数组和单个值?
理想情况下,我将放弃ObjectMapper的配置,以避免将单个对象设置到JSON文档的其他级别。例如,我不想允许:
{
...
"attributes": {
...
}
}
通常这种格式应该是强制性的:
{
...
"attributes": [{
...
}]
}
基于此,我尝试在我的List中放置一个对象包装器来设置我是否能够区分列表和对象。有了这样的东西:
public class ObjectWrapper<T> {
private List<T> list;
private T object;
public boolean isObject() {
return list == null;
}
}
有了这样的资源:
@Path(...)
@Stateless
public class MyRestResource {
@POST
@Consumes(MediaType.APPLICATION_JSON)
public Response create(ObjectWrapper myObjects) {
// Do some stuff there
}
}
并试图通过JAX-RS/Jersey/Jackson机制对我的内容进行反序列化。如果我让解决方案保持现状,反序列化会失败,因为预期的JSON格式如下:
{
"list": [{
"name": "a name",
... // other attributes
}]
}
然后我试图编写一个自定义反序列化程序,但我在这个任务中有点迷失了方向。我有这样的想法:
public class ObjectWrapperDeserializer<T> extends JsonDeserializer<T> {
@Override
public T deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingExcepthtml" target="_blank">ion {
... // What to put there to deserialize Array or Object
}
}
我只想反序列化根级别以将反序列化的内容设置为对象包装器。当完成不同@Provider的配置时,我还希望在一个用@Application ationPath注释的类中配置该功能。
我希望所有的信息都能充分说明我想做什么和我已经测试过什么。
等待关于如何在同一路径上接受数组或对象的资源的建议。
提前非常感谢。
好的,我终于成功地建立了一个机制,它完全符合我的要求。但是,我不确定这样的表现或诸如此类的事情是否会产生负面影响。
首先,我定义了一个可以接受List或单对象的类:
public class RootWrapper<T> {
private List<T> list;
private T object;
}
然后,我需要一个自定义反序列化器,它能够知道要反序列化哪种T类型并处理集合或单个对象。
public class RootWrapperDeserializer extends JsonDeserializer<CollectionWrapper<?>> {
private Class contentType;
public RootWrapperDeserializer(Class contentType) {
this.contentType = contentType;
}
@Override
public RootWrapper deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
// Retrieve the object mapper and read the tree.
ObjectMapper mapper = (ObjectMapper) jp.getCodec();
JsonNode root = mapper.readTree(jp);
RootWrapper wrapper = new RootWrapper();
// Check if the root received is an array.
if (root.isArray()) {
List list = new LinkedList();
// Deserialize each node of the array using the type expected.
Iterator<JsonNode> rootIterator = root.getElements();
while (rootIterator.hasNext()) {
list.add(mapper.readValue(rootIterator.next(), contentType));
}
wrapper.setList(list);
}
// Deserialize the single object.
else {
wrapper.setObject(mapper.readValue(root, contentType));
}
return wrapper;
}
}
据我所知,我尝试只手动反序列化根级别,然后让Jackson负责下一个操作。我只需要知道我希望在Wrapper中出现哪种真正的类型。
在这个阶段,我需要一种方法来告诉泽西/杰克逊使用哪个反序列化器。我发现的一种方法是创建一种反序列化器注册表,其中存储要使用正确的反序列化器进行反序列化的类型。我扩展了反序列化器。基类。
public class CustomDeserializers extends Deserializers.Base {
// Deserializers caching
private Map<Class, RootWrapperDeserializer> deserializers = new HashMap<>();
@Override
public JsonDeserializer<?> findBeanDeserializer(JavaType type,
DeserializationConfig config, DeserializerProvider provider,
BeanDescription beanDesc, BeanProperty property) throws JsonMappingException {
// Check if we have to provide a deserializer
if (type.getRawClass() == RootWrapper.class) {
// Check the deserializer cache
if (deserializers.containsKey(type.getRawClass())) {
return deserializers.get(type.getRawClass());
}
else {
// Create the new deserializer and cache it.
RootWrapperDeserializer deserializer =
new RootWrapperDeserializer(type.containedType(0).getRawClass());
deserializers.put(type.getRawClass(), deserializer);
return deserializer;
}
}
return null;
}
}
好的,然后我有我的反序列化器注册表,它仅按需创建新的反序列化器,并在创建后保留它们。我不确定这种方法是否存在任何并发问题。我知道Jackson做了很多缓存,并且不会每次调用findBeanDeserializer,一旦它在特定的反序列化上下文中第一次被调用。
现在我已经创建了不同的类,我需要做一些管道工程来将所有的东西结合在一起。在创建ObjectMapper的提供程序中,我可以将反序列化器注册表设置为创建的对象映射器,如下所示:
@Provider
@Produces(MediaType.APPLICATION_JSON)
public class JsonObjectMapper implements ContextResolver<ObjectMapper> {
private ObjectMapper jacksonObjectMapper;
public JsonObjectMapper() {
jacksonObjectMapper = new ObjectMapper();
// Do some custom configuration...
// Configure a new deserializer registry
jacksonObjectMapper.setDeserializerProvider(
jacksonObjectMapper.getDeserializerProvider().withAdditionalDeserializers(
new RootArrayObjectDeserializers()
)
);
}
@Override
public ObjectMapper getContext(Class<?> arg0) {
return jacksonObjectMapper;
}
}
然后,我还可以定义我的@Application ationPath,即我的REST应用程序,如下所示:
public abstract class AbstractRestApplication extends Application {
private Set<Class<?>> classes = new HashSet<>();
public AbstractRestApplication() {
classes.add(JacksonFeature.class);
classes.add(JsonObjectMapper.class);
addResources(classes);
}
@Override
public Set<Class<?>> getClasses() {
return classes;
}
@Override
public Set<Object> getSingletons() {
final Set<Object> singletons = new HashSet<>(1);
singletons.add(new JacksonJsonProvider());
return singletons;
}
private void addResources(Set<Class<?>> classes) {
classes.add(SomeRestResource.class);
// ...
}
}
现在,一切就绪,我可以编写一个REST资源方法,如下所示:
@POST
@Path("somePath")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response create(RootWrapper<SpecificClass> wrapper) {
if (wrapper.isObject()) {
// Do something for one single object
SpecificClass sc = wrapper.getObject();
// ...
return Response.ok(resultSingleObject).build();
}
else {
// Do something for list of objects
for (SpecificClass sc = wrapper.getList()) {
// ...
}
return Response.ok(resultList).build();
}
}
仅此而已。不要犹豫,评论解决方案。非常欢迎反馈,尤其是关于反序列化过程的方式,我真的不确定它对性能和并发是否安全。
开发JAX-RS应用程序并解决问题。需要从我的资源中自定义json输出以使用Jackson(2.22.2)解析器而不是默认Moxy(根据此答案)。 这是pom。xml片段 我还配置web.xml文件默认使用Jackson 但是资源输出与我使用注释和序列化器配置的有所不同。这是表示为json的模型 和序列化程序 } 这是资源片段 响应json根本不是定制的。 期望的输出是 谢谢。
我如何告诉Jackson忽略JSON名称? 我有以下POJO: 当我有这样的东西: “ABCName”:“foo”,然后杰克逊没有认出它抛出错误。 它期望的是: “abcName”:“foo”。 代码: 输出:{"abcname":"Foo"} 然后我试着用@JsonProperty(“ABCName”)注释ABCName 在我注释并运行代码之后,我得到的是:{“ABCName”:“Foo”,“A
我有一个带有以下注释的类: 我尝试的是忽略反序列化的json。但它不起作用。始终在 JSON 字符串到达时,Jackson lib 将填充 references 属性。如果我只使用@JsonIgnore注释,则 getter 不起作用。这个问题有什么解决方案吗? 谢啦
我在Java创建了一个REST网络服务。我使用Joda-time作为日期,使用Jackson作为JSON格式。所有内容都上传到Glassfish 4.1服务器上。 avax.ws.rs-api-2.0.1.jar joda-time-2.7.jar jackson-annotation-2.8.8.jar jackson-core-2.8.8.jar jackson-databind-2.8.8.
我一直想知道JacksonFeature。泽西2.17仍然需要上课。我看不出JacksonFeature代码之间的输出有任何区别。类是否已注册。 然后,我从codingpedia中分叉了一个代码,删除了JacksonFeature.class,升级到Spring 4.1.2和jersey 2.17,更新了代码,测试仍然通过。 因此,我创建了一个非常简单的web服务来再次测试这个github链接,考
首先,我不熟悉Jython。我正在寻找一种将python代码集成到Java项目中的方法。因此我正在调查Jython。 我正在尝试将一个 json 字符串转换为 Java 对象 - 在 python 中。 首先,我一直在努力让Jython找到我的java类。由于缺乏更优雅的解决方案,我可以通过简单地执行以下操作来向前迈进: 无论如何。。。 我正在尝试以下操作: 但是,在运行时,我收到以下错误: 我不