Статьи

Oracle WebLogic 12.1.2 теперь с помощью EclipseLink MOXy JSON-Binding

Oracle WebLogic 12.1.2 теперь доступен . WebLogic 12.1.2 содержит EclipseLink 2.4.2, это означает, что впервые JSON-привязка EclipseLink MOXy доступна в WebLogic «из коробки». Я продемонстрирую преимущества использования MOXy для JSON-привязки на примере.
Модель Java

Ниже приведена модель Java, которую мы будем использовать для этого поста. Эти же метаданные будут использоваться для настройки XML и JSON, создаваемых нашей службой JAX-RS. Методы get / set были опущены для экономии места.

Клиент 

Ниже представлено простое представление клиента. Я аннотировал пару полейрасширениемMOXy @XmlPath (см.  XPath Based Mapping ), чтобы продемонстрировать, где MOXy действительно используется.

package org.example.model;
 
import java.util.*;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;
 
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Customer {
 
    @XmlAttribute(name="id")
    private int identifier;
    
    @XmlPath("personalInfo/firstName/text()")
    private String firstName;
     
    @XmlPath("personalInfo/lastName/text()")
    @XmlElement(nillable=true)
    private String lastName;
 
    @XmlElementWrapper
    @XmlElement(name="phoneNumber")
    private List<PhoneNumber> phoneNumbers = new ArrayList<PhoneNumber>();
 
}

PhoneNumber 

Мы отобразим класс PhoneNumber на сложный тип с простым содержимым (см.  JAXB и Сложные типы с простым содержимым ), чтобы увидеть влияние на JSON-привязку.

package org.example.model;
 
import javax.xml.bind.annotation.*;
 
@XmlAccessorType(XmlAccessType.FIELD)
public class PhoneNumber {
 
    @XmlAttribute
    private String type;
     
    @XmlValue
    private String value;
 
}

package-info 

Мы будем использовать аннотацию @XmlSchema уровня пакета, чтобы пространство имен квалифицировало результирующий XML (см .: JAXB & Namespaces ), чтобы мы могли увидеть влияние на представление JSON.

@XmlSchema(
    namespace="http://www.example.org/model",
    elementFormDefault=XmlNsForm.QUALIFIED)
package org.example.model;
 
import javax.xml.bind.annotation.*;

Служба RESTful

CustomerResource 

Обычно JPA поддерживает реальную службу для выполнения операций персистентности (см.  Создание веб-службы RESTful — часть 4/5 ). Но для этого поста я буду использовать сервис в стиле «Hello World», который возвращает Customer на основе идентификатора в виде XML и JSON, чтобы проиллюстрировать некоторые моменты, связанные с привязкой.

package org.example.service;
 
import javax.ejb.*;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import org.example.model.*;
 
@Stateless
@LocalBean
@Path("/customers")
public class CustomerResource {
 
    @GET
    @Produces({
        MediaType.APPLICATION_XML,
        MediaType.APPLICATION_JSON
    })
    @Path("{id}")
    public Customer read(@PathParam("id") int id) {
        Customer customer = new Customer();
        customer.setId(id);
        customer.setFirstName("Jane");
        customer.setLastName(null);
         
        PhoneNumber pn = new PhoneNumber();
        pn.setType("work");
        pn.setValue("5551111");
        customer.getPhoneNumbers().add(pn);
         
        return customer;
     }
 
}

CustomerApplication 

Moxy сконфигурирован как JSON-связывания поставщика с использованием MOXyJsonProvider класса через JAX-RS Application класса (см Moxy в качестве JAX-RS JSON поставщика — MOXyJsonProvider ).  MOXyJsonProvider предлагает различные настройки, которые вы можете использовать для настройки представления JSON. В этом примере мы будем использовать свойство wrapperAsArrayName для очистки представления коллекций (см .:  Привязка к JSON & XML — Обработка коллекций ).

package org.example.service;
 
import java.util.*;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
import org.eclipse.persistence.jaxb.rs.MOXyJsonProvider;
  
@ApplicationPath("rest/*")
public class CustomerApplication  extends Application {
 
    @Override
    public Set<Class<?>> getClasses() {
        HashSet<Class<?>> set = new HashSet<Class<?>>(1);
        set.add(CustomerResource.class);
        return set;
    }
  
    @Override
    public Set<Object> getSingletons() {
        MOXyJsonProvider moxyJsonProvider = new MOXyJsonProvider();
        moxyJsonProvider.setWrapperAsArrayName(true);
  
        HashSet<Object> set = new HashSet<Object>(1);
        set.add(moxyJsonProvider);
        return set;
    }
 
}

Выходные данные

Мы рассмотрим выходные данные, полученные при обращении к нашему сервису по следующему URL-адресу с использованиемтипов носителей application / xml и application / json .

http://localhost:7001/CustomerResource/rest/customers/1

XML

Ниже приведен пример вывода XML. Это не удивительно, поскольку оно точно соответствует метаданным JAXB и MOXy, которые мы применили к нашей модели.

<?xml version="1.0" encoding="UTF-8"?>
<customer
    xmlns="http://www.example.org/model" id="1">
    <personalInfo>
        <firstName>Jane</firstName>
        <lastName
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
    </personalInfo>
    <phoneNumbers>
        <phoneNumber type="work">5551111</phoneNumber>
    </phoneNumbers>
</customer>

Обратите внимание на следующие специфичные для XML вещи об этом выводе.

  1. Существует корневой элемент (строка 2).
  2. XML соответствует пространству имен. (строка 3).
  3. Есть атрибуты XML (строки 3 и 10).
  4. Идентификатор атрибут содержит Int значение (строка 3).
  5. XSI: ноль атрибут используется для указания того, что ЬавЬЫате элемент содержит нулевое значение. (строки 6 и 7).
  6. Существует коллекция элементов phoneNumber с группирующим элементом phoneNumbers (строки 9-11).

JSON

Ниже приведен ответ JSON, когда используется привязка JSON MOXy с использованием
MOXyJsonProvider . Он был создан с использованием тех же метаданных, что и представление XML, но все элементы, специфичные для XML, пропали, и вместо них используются элементы, специфичные для JSON.

{
    "id": 1,
    "personalInfo": {
        "firstName": "Jane",
        "lastName": null
    },
    "phoneNumbers": [
        {
            "type": "work",
            "value": "5551111"
        }
    ]
}

Теперь давайте сравним вывод JSON с тем, что WebLogic произвел бы по умолчанию. По умолчанию WebLogic использует свою реализацию JAXB с промежуточной библиотекой для преобразования событий XML в / из JSON. Поскольку MOXy является реализацией JAXB по умолчанию в WebLogic, применяется аннотация @XmlPath , но мы не получаем никаких других преимуществ от JSON-привязки MOXy.

{
    "@id": "1",
    "personalInfo": {
        "firstName": "Jane",
        "lastName": {
            "@nil": "true"
        }
    },
    "phoneNumbers": {
        "phoneNumber": {
            "@type": "work",
            "$": "5551111"
        }
    }
}

Ниже приведены некоторые проблемы, которые мы видим с представлением по умолчанию, которого не было при использовании JSON-привязки MOXy. Все они из-за утечки представления XML в представление JSON.

  1. Ключи, соответствующие свойствам, сопоставленным с @XmlAttribute, имеют префикс @ (строки 2 и 11).
  2. Значение int для свойства id неправильно записано в виде строки JSON (строка 2).
  3. Пустое JSON-представление не используется для ключа lastName (строки 5-7).
  4. Наш список из PHONENUMBER объектов не были ранжированы правильно , так как массив JSON размера 1 (строки 10-13).
  5. Наше свойство phoneNumbers будет отображаться в ключ JSON для phoneNumber вместо phoneNumbers (строка 10).