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