Ввод/вывод JSON службы отдыха трикотажа не работает в javascript

Мне нравится создавать службу отдыха с вводом и выводом xml и json. Выходные данные xml должны быть действительными и определены в схеме xsd с использованием пространства имен. С помощью xml сервис работает хорошо. Для json я не нашел решения для обеспечения согласованного ввода и вывода. Чтобы проиллюстрировать мою проблему, я сделал небольшой пример. Я создал два класса с аннотациями jaxb Parent и Child. У родителя есть @XmlAttribute и список дочерних объектов. Остальная служба может генерировать два примера родительских объектов. Один пример с одним ребенком и другой пример с двумя детьми. Потому что есть некоторые различия между нотациями, имеющими список с одним или несколькими членами. Кроме того, у службы есть метод @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;
  }

}

Ребенок

@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 и возможности отправки той же нотации в службу отдыха джерси?


person Markus    schedule 13.09.2013    source источник


Ответы (1)


Мне удалось это, обновив до более новой версии трикотажа. Теперь я использую 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;
    }
}

После этого естественную нотацию можно использовать для операций ввода и вывода остальных сервисов.

person Markus    schedule 19.09.2013