Jersey + Jackson JSON Datumsformat Serialisierung - wie das Format oder die Verwendung benutzerdefinierte JacksonJsonProvider ändern

StackOverflow https://stackoverflow.com/questions/4428109

Frage

Ich bin mit Jersey + Jackson REST JSON-Dienste-Schicht für meine Anwendung zu liefern. Das Problem, das ich habe, ist, dass die Standarddatum Serialisierungsformat sieht wie folgt aus:

"CreationDate":1292236718456

Zuerst dachte ich, es ist ein UNIX-Zeitstempel ist ... aber es ist zu lang dafür. Mein Client-seitige JS-Bibliothek hat Probleme Deserialisieren dieses Format (es eine Reihe von verschiedenen Datumsformate unterstützt aber nicht diese nehme ich an). Ich möchte das Format ändern, so dass es von meiner Bibliothek verzehrbar sein kann (ISO zum Beispiel). Wie kann ich das tun ... fand ich ein Stück Code, das helfen könnte, aber ... wo ich es, als ich die Jackson Serializer Instanziierung nicht kontrollieren (Jersey tut)?

objectMapper.configure(
    SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false);

Ich fand auch den Code für benutzerdefinierte JacksonJsonProvider - die Frage .. ist wie mache ich alle meine POJO Klassen, die es verwenden,

?
@Provider
public class MessageBodyWriterJSON extends JacksonJsonProvider {

    private static final String DF = "yyyy-MM-dd’T'HH:mm:ss.SSSZ";

    @Override
    public boolean isWriteable(Class arg0, Type arg1, Annotation[] arg2,
            MediaType arg3) {
        return super.isWriteable(arg0, arg1, arg2,
                arg3);
    }
    @Override
    public void writeTo(Object target, Class arg1, Type arg2, Annotation[] arg3,
            MediaType arg4, MultivaluedMap arg5, OutputStream outputStream)
            throws IOException, WebApplicationException {
            SimpleDateFormat sdf=new SimpleDateFormat(DF);

        ObjectMapper om = new ObjectMapper();
        om.getDeserializationConfig().setDateFormat(sdf);
        om.getSerializationConfig().setDateFormat(sdf);
        try {
            om.writeValue(outputStream, target);
        } catch (JsonGenerationException e) {
            throw e;
        } catch (JsonMappingException e) {
            throw e;
        } catch (IOException e) {
            throw e;
        }
    }
}
War es hilfreich?

Lösung

Für das, was es wert ist, diese Zahl ist Standard-Java-Zeitstempel (von JDK-Klassen verwendet werden); Unix speichern Sekunden, Java Millisekunden, weshalb es ist etwas größer Wert.

Ich hoffe, es gibt einige Dokumente, wie in Jersey zu injizieren ObjectMapper (es soll die übliche Art und Weise folgt bereitgestellte Objekt zu injizieren). Aber alternativ können Sie außer Kraft setzen JacksonJaxRsProvider angeben / configure ObjectMapper und registrieren, dass; das ist, was Jersey selbst tut, und es gibt mehr Möglichkeiten, es zu tun.

Andere Tipps

Ich schaffte es in Resteasy „die JAX-RS Art und Weise“ zu tun, so dass es erfolgreich auf jeder konformen Implementierung wie Jersey (vor kurzem auf JEE7 Server Wildfly 8 getestet funktionieren soll, ist es erforderlich, nur ein paar Änderungen an den Jackson Teil, weil sie einige APIs geändert).

Sie müssen eine ContextResolver (Scheck, der den richtigen Content-Type Produziert enthält) definieren:

import javax.ws.rs.ext.ContextResolver;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
import org.codehaus.jackson.map.DeserializationConfig;
import javax.ws.rs.ext.Provider;
import javax.ws.rs.Produces; 
import java.text.SimpleDateFormat;
@Provider
@Produces("application/json")
public class JacksonConfigurator implements ContextResolver<ObjectMapper> {

    private ObjectMapper mapper = new ObjectMapper();

    public JacksonConfigurator() {
        SerializationConfig serConfig = mapper.getSerializationConfig();
        serConfig.setDateFormat(new SimpleDateFormat(<my format>));
        DeserializationConfig deserializationConfig = mapper.getDeserializationConfig();
        deserializationConfig.setDateFormat(new SimpleDateFormat(<my format>));
        mapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false);
    }

    @Override
    public ObjectMapper getContext(Class<?> arg0) {
        return mapper;
    }

}

Dann müssen Sie die neu erstellte Klasse zurückkehren in Ihrem javax.ws.rs.core.Application der getClasses

import javax.ws.rs.core.Application;
public class RestApplication extends Application {

     @Override
     public Set<Class<?>> getClasses() {
         Set<Class<?>> classes = new HashSet<Class<?>>();
         // your classes here
         classes.add(JacksonConfigurator.class);
         return classes;
      }

}

auf diese Weise alle Operation gemacht durch jackson die ObjectMapper Ihrer Wahl gegeben werden.

EDIT: Vor kurzem fand ich meine Kosten aus, dass mit Resteasy 2.0.1 (und damit Jackson 1.5.3) gibt es ein seltsames Verhalten, wenn Sie sich entscheiden, den JacksonConfigurator zu erweitern individuelle Zuordnungen hinzufügen

.
import javax.ws.rs.core.MediaType;
@Provider
@Produces(MediaType.APPLICATION_JSON)
public class MyJacksonConfigurator extends JacksonConfigurator

Wenn Sie gerade tun, wie folgt (und natürlich auch die erweiterte Klasse in RestApplication setzen), um den Mapper der Elternklasse verwendet wird, dass Sie die benutzerdefinierten Zuordnungen verlieren wird. Um es ich tun musste, etwas richtig arbeiten, die mir nutzlos scheint anders:

public class MyJacksonConfigurator extends JacksonConfigurator implements ContextResolver<ObjectMapper> 

Ihre eigene ObjectMapper konfigurieren, müssen Sie Ihre eigene Klasse, die Geräte ContextResolver

injizieren

Wie genau Trikot bekommen diese holen wird Art auf Ihrem IOC abhängen (Frühling, guice). Ich benutze Frühling, und meine Klasse sieht ungefähr wie folgt aus:

import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;

import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig.Feature;
import org.codehaus.jackson.map.deser.CustomDeserializerFactory;
import org.codehaus.jackson.map.deser.StdDeserializerProvider;
import org.codehaus.jackson.map.ser.CustomSerializerFactory;
import org.springframework.stereotype.Component;

// tell spring to look for this.
@Component
// tell spring it's a provider (type is determined by the implements)
@Provider
public class ObjectMapperProvider implements ContextResolver<ObjectMapper> {
    @Override
    public ObjectMapper getContext(Class<?> type) {
        // create the objectMapper.
        ObjectMapper objectMapper = new ObjectMapper();
        // configure the object mapper here, eg.
           objectMapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false);
        return objectMapper;
    }
}

Wenn Sie zur Arbeit wählen mit Joda Datetime auf Ihrem Server-Objekte und wollen serialisiert zu ISO8601 könnten Sie Jackson JodaModule . Sie können ein Jersey-Provider registrieren, wie folgt:

import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.joda.JodaModule;

@Provider
public class MyObjectMapperProvider implements ContextResolver<ObjectMapper> {

  final ObjectMapper objectMapper;

  public MyObjectMapperProvider() {
    objectMapper = new ObjectMapper();
    /* Register JodaModule to handle Joda DateTime Objects. */
    objectMapper.registerModule(new JodaModule());
    /* We want dates to be treated as ISO8601 not timestamps. */
    objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
  }

  @Override
  public ObjectMapper getContext(Class<?> arg0) {
    return objectMapper;
  }
}

Weitere Informationen über Jersey Webseite .

Ich hatte das gleiche Problem (mit Jersey + Jackson + Json), der Client sendete ein Datum, aber es wurde in dem Server geändert, wenn die Daten in das Objekt zugeordnet wurden.

Ich folgte anderen Ansatz, um dies zu lösen, indem Sie diesen Link lesen: http://blog.bdoughan.com/2010/07/xmladapter-jaxbs-secret-weapon.html , als ich feststellte, dass das empfangene Datum ein Timestamp war (das gleiche wie Adrin in seiner Frage: "creationDate":1292236718456)

In meinem VO-Klasse habe ich diese Anmerkung zu dem Attribut @XmlJavaTypeAdapter und auch eine innere Klasse Wich erweiterte XmlAdapter umgesetzt:

@XmlRootElement
public class MyClassVO {
   ...
   @XmlJavaTypeAdapter(DateFormatterAdapter.class) 
   Date creationDate;
   ...

   private static class DateFormatterAdapter extends XmlAdapter<String, Date> {
      @Override
      public Date unmarshal(final String v) throws Exception {
         Timestamp stamp = new Timestamp(new Long(v));
         Date date = new Date(stamp.getTime());
         return date;
      }
}

Ich hoffe, dass es auch Ihnen helfen könnte.

Im Folgenden Code für mich gearbeitet - JAX-RS 1.1, Jersy 1.8

import java.text.SimpleDateFormat;

import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.Provider;

import org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider;
import org.codehaus.jackson.map.DeserializationConfig;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;


@Provider
@Produces(MediaType.APPLICATION_JSON)
public class JsonProvider extends JacksonJaxbJsonProvider {
  private static final ObjectMapper objectMapper = new ObjectMapper();
  static {
    // allow only non-null fields to be serialized
    objectMapper.getSerializationConfig().setSerializationInclusion(Inclusion.NON_NULL);

    SerializationConfig serConfig = objectMapper.getSerializationConfig();
    serConfig.setDateFormat(new SimpleDateFormat(<your date format>));
    DeserializationConfig deserializationConfig = objectMapper.getDeserializationConfig();
    deserializationConfig.setDateFormat(new SimpleDateFormat(<your date format>));
    objectMapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false);

  }

  public JsonProvider() {
    super.setMapper(objectMapper);
  }
}

Geben Sie den MessageBodyWriter JSON mit diesem

import javax.ws.rs.core.MediaType; 
import javax.ws.rs.ext.Provider; 

import org.codehaus.jackson.jaxrs.JacksonJsonProvider; 
import org.codehaus.jackson.map.ObjectMapper; 
import org.codehaus.jackson.map.SerializationConfig; 

@Provider 
public class MessageBodyWriterJSON extends JacksonJsonProvider { 
            public MessageBodyWriterJSON (){ 
            } 

        @Override 
            public ObjectMapper locateMapper(Class<?> type, MediaType mediaType) 
        { 
        ObjectMapper mapper = super.locateMapper(type, mediaType); 
        //DateTime in ISO format "2012-04-07T17:00:00.000+0000" instead of 'long' format 
            mapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false); 
            return mapper; 
        } 
}

json-io ( https://github.com/jdereg/json-io ) ist eine komplette Java / von Serialisierung Bibliothek JSON. Wenn es mit dem JSON-String zu schreiben, können Sie wie Daten formatiert sind. Standardmäßig werden Daten so lange geschrieben (wie oben, die Millisekunden seit Jan 1, 1970). Allerdings können Sie es ein Format String oder Java DateFormatter geben und haben die Daten geschrieben, was auch immer Format, das Sie möchten.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top