javascript - Jersey 休息服务的 JSON 输入/输出在 JavaScript 中无法使用

标签 javascript json rest jaxb jersey-1.0

我喜欢构建一个带有 xml 和 json 输入和输出的 Rest 服务。 xml 输出应该有效并使用命名空间在 xsd 架构中定义。使用 xml 服务运行良好。对于 json,我还没有找到实现一致输入和输出的解决方案。 为了说明我的问题,我做了一个小例子。我创建了两个带有 jaxb 注释的类 Parent 和 Child。父对象有一个 @XmlAttribute 和一个子对象列表。其余服务可以生成两个示例父对象。一个示例包含一个 child ,另一个示例包含两个 child 。因为具有一个或多个成员的列表的符号之间存在一些差异。此外,该服务还有一个 @POST 方法,它接收父对象并直接返回它。我的假设是将生成的 json 文本放入 post 方法中并获得与以前相同的符号。但这对于大多数情况不起作用。

我的休息服务:

@Path("parent")
public class ParentResource {

    @GET
    @Produces ({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
    public Parent generateExample(){
        Parent father = new Parent();
        father.setName("peter");

        Child john = new Child();
        john.setName("john");

        father.getChildren().add(john);

        return father;
    }

    @GET
    @Path("list")
    @Produces ({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
    public Parent generateExample2(){
    Parent father = new Parent();
    father.setName("peter");

    Child john = new Child();
    john.setName("john");
    Child sue = new Child();
    sue.setName("sue");

    father.getChildren().add(john);
    father.getChildren().add(sue);

    return father;
    }


    @POST
    @Produces ({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
    @Consumes ({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
    public Parent echoEntity(Parent input){
        return input;
    }
}

父级

@XmlAccessorType (XmlAccessType.NONE)
@XmlRootElement (name="parent")
public class Parent  implements Serializable{

   @XmlAttribute
  private String name;

  @XmlElement 
  private List<Child> children = null;

  public String getName() {
     return name;
  }

  public void setName(String name) {
     this.name = name;
  }

  public List<Child> getChildren() {
     if(children == null){
        children = new LinkedList<Child>();
     }
     return children;
  }

  public void setChildren(List<Child> children) {
     this.children = children;
  }

}

child

@XmlAccessorType (XmlAccessType.NONE)
@XmlRootElement (name="child")
public class Child  implements Serializable {

    @XmlElement
    private String name;

    public String getName() {
       return name;
    }

    public void setName(String name) {
       this.name = name;
    }
}

package-info.java在Parent+Child包中定义命名空间。

@javax.xml.bind.annotation.XmlSchema(namespace="http://myexample.com",
    elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED, 
    attributeFormDefault = javax.xml.bind.annotation.XmlNsForm.UNQUALIFIED)

自定义上下文解析器

@Provider
@Produces (MediaType.APPLICATION_JSON)
@Consumes (MediaType.APPLICATION_JSON)
public class CustomResolver implements ContextResolver<JAXBContext>{
    private final JAXBContext context;
    private final Set<Class<?>> types;
    private final Class<?>[] cTypes = {
       Parent.class, Child.class
    };

    public CustomResolver() throws Exception {
        this.types = new HashSet<Class<?>>(Arrays.asList(cTypes));


        Map<String, String> nsMap = new HashMap<String, String>();
        nsMap.put("http://myexample.com", "ex");

        JSONConfiguration config = JSONConfiguration.natural().rootUnwrapping(false).build();
//      JSONConfiguration config = JSONConfiguration.mapped().xml2JsonNs(nsMap).attributeAsElement("name").rootUnwrapping(false).build();
//      JSONConfiguration config = JSONConfiguration.mapped().attributeAsElement("name").rootUnwrapping(false).build();
//      JSONConfiguration config = JSONConfiguration.mappedJettison().build();
//      JSONConfiguration config = JSONConfiguration.badgerFish().build();

        context = new JSONJAXBContext(config, cTypes);
    }

    public JAXBContext getContext(Class<?> objectType) {
        return (types.contains(objectType)) ? context : null;
    }
}

Rest 应用程序包括自定义上下文解析器

public class RestApplication extends Application {
    private Set<Object> singletons = new HashSet<Object>();
    private Set<Class<?>> classes = new HashSet<Class<?>>();

    public RestApplication(){
        singletons.add(new ParentResource());

        classes.add(CustomResolver.class);
    }

    @Override
    public Set<Class<?>> getClasses(){
        return classes;
    }

    @Override
    public Set<Object> getSingletons(){
        return singletons;
    }
}

没有自定义上下文解析器的测试结果(应用程序中的评论):

generated 1 :
{"@name":"peter","children":{"name":"john"}}
output of post method :
{"@name":"peter"}

generated 2 :
{"@name":"peter","children":[{"name":"john"},{"name":"sue"}]}
output of post method :
{"@name":"peter"}

使用自然符号的测试结果(我喜欢使用这种符号)

generated 1 :
{"parent":{"name":"peter","children":[{"name":"john"}]}}
output of post method :
Exception: The request sent by the client was syntactically incorrect ()

generated 2 :
{"parent":{"name":"peter","children":[{"name":"john"},{"name":"sue"}]}}
output of post method :
Exception: The request sent by the client was syntactically incorrect ()

使用映射符号且没有命名空间映射的测试结果

generated 1 :
{"parent":{"name":"peter","children":{"name":"john"}}}
output of post method :
The request sent by the client was syntactically incorrect ()

generated 2 :
{"parent":{"name":"peter","children":[{"name":"john"},{"name":"sue"}]}}
output of post method :
The request sent by the client was syntactically incorrect ()

带有映射符号的测试结果

generated 1 :
{"ex.parent":{"name":"peter","ex.children":{"ex.name":"john"}}}
output of post method :
{"ex.parent":{"name":"peter","ex.children":{"ex.name":"john"}}}

generated 2 :
{"ex.parent":{"name":"peter","ex.children":[{"ex.name":"john"},{"ex.name":"sue"}]}}
output of post method :
{"ex.parent":{"name":"peter","ex.children":[{"ex.name":"john"},{"ex.name":"sue"}]}}

哇,它有效。但我不喜欢在 JavaScript 中使用这种表示法。命名空间前缀合并到属性名称中。当访问嵌套元素时,这对于在 javascript 客户端中硬编码前缀不太有用。前缀名称可能会改变! 使用抛弃符号,它看起来比之前的例子更糟糕。

说来话长,但问题很简单。有人有解决方案来接收 json 自然符号并能够将相同的符号发送到 Jersey 休息服务吗?

最佳答案

我通过更新到较新的 Jersey 版本来管理它。现在我使用1.13,之前它已经很旧了1.1.5.1。我也必须做同样的改变。在自定义上下文解析器中,我删除了注释 @Consumes (MediaType.APPLICATION_JSON) 并添加一个新类并将其添加到应用程序类中的类

@Provider
@Consumes (MediaType.APPLICATION_JSON)
public class NaturalJsonReader implements MessageBodyReader{

    private static final JSONConfiguration jConfig = JSONConfiguration.natural().rootUnwrapping(false).build();

    @Override
    public boolean isReadable(Class arg0, Type type, Annotation[] arg2, MediaType mt) {
        return true;
    }

    @Override
    public Object readFrom(Class arg0, Type arg1, Annotation[] arg2, MediaType arg3, MultivaluedMap arg4, InputStream arg5) throws IOException, WebApplicationException {

        try {
             JSONUnmarshaller m = new JSONJAXBContext(jConfig, arg0).createJSONUnmarshaller();
             Object o = m.unmarshalJAXBElementFromJSON(arg5, arg0).getValue(); 
             return o;
        } catch (JAXBException e) {
        }

        return null;
    }
}

此后,自然符号可以用于其余服务的输入和输出操作。

关于javascript - Jersey 休息服务的 JSON 输入/输出在 JavaScript 中无法使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18787000/

相关文章:

java - 在Android中解析JSON数据

php - 如何在 swift json 请求中传递数组

java.lang.ClassNotFoundException : Cannot find implementation for com. 如何处理java.demo.mapper.MapperDTO

ios - 从 Swift 函数中的异步调用返回数据

javascript - 填满剩余高度

javascript - 获取 html div 的确切内容

javascript - 是否有一种非循环每个单个列表项的方法来查找唯一的列表项?

javascript - md-datepicker 从数组中过滤日期

javascript - 可以在javascript中使用JSON编辑JSON吗

REST - GET 返回与 POST/PUT 不同的结果