Что такое мокси-эквивалент JsonAnySetter Джексона?

Я пытаюсь перейти на Джерси 2.0. Что доставляет мне боль с Джексоном, и документы рекомендуют использовать Moxy.

Я заставил Moxy работать с вызовами get и post, где все хорошо совпадает, однако мне нужно иметь дело с возможными неизвестными элементами.

// Handle unknown deserialization parameters
@JsonAnySetter
protected void handleUnknown(String key, Object value) {
    if (unknownParameters == null) {
        unknownParameters = new HashMap<>();
    }
    unknownParameters.put(key, value);
}

Это хорошо работало до перехода на майку 2.0, и хотя это не вызывает никаких проблем, когда я оставляю его в нем, оно никогда не вызывается.

Как реализовать это в Джерси 2.0? Я в порядке с Мокси или Джексоном.

мои зависимости

'org.codehaus.jackson:jackson-mapper-asl:1.9.2',
'org.eclipse.persistence:org.eclipse.persistence.moxy:2.5.0',
'org.glassfish.jersey.media:jersey-media-moxy:2.0',

Это не влияет на мой web.xml

<init-param>
    <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
    <param-value>true</param-value>
</init-param>

person Diver    schedule 05.08.2013    source источник
comment
Я понятия не имею, почему кто-то рекомендует использовать MOXy для JSON (насколько мне известно, у него те же проблемы, что и у Jettison); его поддержка XML, вероятно, хороша, но поддержка JSON кажется сомнительной. Поэтому убедитесь, что вы знаете, почему вы предпочитаете одну реализацию другой.   -  person StaxMan    schedule 18.10.2013


Ответы (3)


Вы можете использовать модуль jersey-media-json-jackson вместо MOXy, чтобы воспользоваться аннотацией (я не уверен, поддерживает ли MOXy аналогичную функцию). Всего несколько заметок:

  • удалите параметр инициализации com.sun.jersey.api.json.POJOMappingFeature из вашего web.xml - Джерси 2.x не распознает это свойство (это специфично для Джерси 1.x)
  • удалить org.glassfish.jersey.media:jersey-media-moxy:2.0 зависимость
  • добавьте зависимость org.glassfish.jersey.media:jersey-media-json-jackson:2.0 и зарегистрируйте JacksonFeature в своем приложении (см. ниже )

После этих шагов Джексон должен обрабатывать Object‹->JSON (un)marshalling и должен распознавать @JsonAnySetter.

Чтобы зарегистрировать JacksonFeature в своем приложении, см. специальный раздел в руководстве пользователя (8.1.4 Джексон):

// Create JAX-RS application.
final Application application = new ResourceConfig()
        .packages("org.glassfish.jersey.examples.jackson")
        .register(MyObjectMapperProvider.class)  // No need to register this provider if no special configuration is required.
        .register(JacksonFeature.class);
person Michal Gajdos    schedule 06.08.2013
comment
Это также отвечает на аналогичный вопрос stackoverflow.com/questions/17622672/ Я спросил некоторое время назад. - person Diver; 06.08.2013

Примечание. Я EclipseLink JAXB (MOXy)< /strong> руководитель и участник JAXB (JSR- 222) группа экспертов.

MOXy не имеет прямого эквивалента @JsonAnySetter Джексона. Я ввел следующий запрос на улучшение, чтобы добавить этот тип поведения:

Ниже приведена некоторая информация о некоторых расширениях MOXy, которые могут быть применимы к вашему варианту использования.


MOXy's @XmlVirtualAccessMethods

Если свойства JSON на самом деле не неизвестны, они просто не существуют как свойства в вашей модели домена, тогда вы можете использовать расширение MOXy @XmlVirtualAccessMethods (см.: http://blog.bdoughan.com/2011/06)./extensible-models-with-eclipselink-jaxb.html) .

Модель Java

Клиент

Аннотация методов @XmlVirtualAccess используется для указания того, что класс Customer является расширяемым.

import java.util.*;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlVirtualAccessMethods;

@XmlVirtualAccessMethods(setMethod = "put")
@XmlAccessorType(XmlAccessType.FIELD)
public class Customer {

    private String firstName;
    private Address billingAddress;

    @XmlTransient
    private Map<String, Object> extensions = new HashMap<String, Object>();

    public <T> T get(String property) {
        return (T) extensions.get(property);
    }

    public void put(String property, Object value) {
        extensions.put(property, value);
    }

}

Адрес

package forum18068176;

public class Address {

    private String street;

    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }

}

Документ сопоставления (oxm.xml)

Определения свойств расширения определены в документе сопоставления MOXy (см.: http://blog.bdoughan.com/2011/04/moxys-xml-metadata-in-jax-rs-service.html).

<?xml version="1.0"?>
<xml-bindings
    xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
    package-name="forum18068176">
    <java-types>
        <java-type name="Customer">
            <xml-type prop-order="firstName lastName billingAddress shippingAddress"/>
            <java-attributes>
                <xml-element
                    java-attribute="lastName"
                    type="java.lang.String"/>
                <xml-element
                    java-attribute="shippingAddress"
                    type="forum18068176.Address"/>
            </java-attributes>
        </java-type>
    </java-types>
</xml-bindings>

Демо

Ниже приведен отдельный демонстрационный код, который вы можете запустить, чтобы увидеть, как все работает. Вам нужно будет указать MOXy в качестве поставщика JAXB (см.: http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html).

package forum18068176;

import java.util.*;
import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;
import org.eclipse.persistence.jaxb.JAXBContextProperties;

public class Demo {

    public static void main(String[] args) throws Exception {
        Map<String, Object> properties = new HashMap<String, Object>(1);
        properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, "forum18068176/oxm.xml");
        properties.put(JAXBContextProperties.MEDIA_TYPE, "application/json");
        properties.put(JAXBContextProperties.JSON_INCLUDE_ROOT, false);
        JAXBContext jc = JAXBContext.newInstance(new Class[] {Customer.class}, properties);

        // Unmarshal JSON
        Unmarshaller unmarshaller = jc.createUnmarshaller();
        StreamSource json = new StreamSource("src/forum18068176/input.json");
        Customer customer = unmarshaller.unmarshal(json, Customer.class).getValue();

        // Access Extension Properties
        String lastName = customer.<String>get("lastName");
        Address shippingAddress = customer.<Address>get("shippingAddress");

        // Marshal Objects
        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(customer, System.out);
    }

}

ввод.json/вывод

{
   "firstName" : "Jane",
   "lastName" : "Doe",
   "billingAddress" : {
      "street" : "1 A Street"
   },
   "shippingAddress" : {
      "street" : "2 B Road"
   }
}

Расширение MOXy @XmlVariableNode с XmlAdapter

Если все неизвестные элементы относятся к одному типу, вы можете использовать комбинацию @XmlVariableNode MOXy (см.: http://blog.bdoughan.com/2013/06/moxys-xmlvariablenode-json-schema.html) и XmlAdapter, чтобы получить желаемый результат:

person bdoughan    schedule 06.08.2013
comment
Спасибо за отличный пример. Часть того, что я делаю, включает в себя преобразование данных из внешних источников, поэтому мне нужно сохранить неизвестные, чтобы кто-то мог их посмотреть. - person Diver; 06.08.2013

Джерси 2.0 должен нормально работать с немодифицированными провайдерами JAX-RS Jackson 2.x из https://github.com/FasterXML/jackson-jaxrs-providers. Нет необходимости что-либо настраивать через web.xml, так как провайдер использует интерфейс поставщика услуг. Единственная потенциальная проблема может возникнуть из-за наличия нескольких поставщиков для одного и того же типа носителя.

Просто убедитесь, что вы используете 2.x (например, 2.2.2) версии зависимостей Jackson. Хотя версии Jackson 1.x и 2.x могут сосуществовать, зависимости между модулями должны совпадать (то есть провайдер 2.2 JAX-RS зависит от jar-файлов jackson-core и jackson-databind 2.2).

person StaxMan    schedule 05.08.2013
comment
и отрицательный голос был за...? (учитывая часть того, что я в порядке с Мокси или Джексоном, о котором идет речь) - person StaxMan; 18.10.2013
comment
Не уверен, почему это не набирает больше голосов - авторегистрация работает отлично. - person thewaterwalker; 08.01.2014