私はこのようなAPIから来る日付フォーマットを持っています:
"start_time": "2015-10-1 3:00 PM GMT+1:00"
これはYYYY-DD-MMです。HH:MM午前/午後のGMTタイムスタンプ。この値をPOJOのDate変数にマッピングしています。明らかに、その表示変換エラーです。
私は2つのことを知りたいのですが:
Jacksonで変換を実行するために必要なフォーマットは何ですか? Dateはこれに適したフィールドタイプですか?
Date
はこのためのファインフィールド型です。 ObjectMapper.setDateFormat
を使用すると、JSONを非常に簡単に解析可能にすることができます。
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm a z");
myObjectMapper.setDateFormat(df);
一般に、変数がJacksonによってObjectメンバーにマップされる前にそれらを処理する方法はありますか?フォーマットの変更、計算など.
はい。カスタムのJsonDeserializer
を実装するなど、いくつかの選択肢があります。 JsonDeserializer<Date>
を拡張します。 これ は良いスタートです。
Jackson v2.0以降、@ JsonFormatアノテーションを直接Objectメンバーに使用することができます。
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm a z")
private Date date;
もちろん自動化された方法がありますはシリアライゼーションとデシリアライゼーションと呼ばれ、pb2qでも言及されているように特定のアノテーション(@JsonSerialize、@JsonDeserialize)で定義できます。 。
Java.util.DateとJava.util.Calendar ...、そしておそらくJodaTimeも使えます。
@JsonFormatアノテーションは私が望んでいたようには動作しませんでした(これには別の値にタイムゾーンを調整したがあります)デシリアライゼーション中(シリアル化は完璧に動作しました):
@JsonFormat(locale = "hu", shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm", timezone = "CET")
@JsonFormat(locale = "hu", shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm", timezone = "Europe/Budapest")
予測結果が欲しい場合は@JsonFormatアノテーションの代わりにカスタムシリアライザとカスタムデシリアライザを使用する必要があります。私はここで本当に良いチュートリアルと解決策を見つけました http://www.baeldung.com/jackson-serialize-dates
Dateフィールドの例がありますが、私はCalendarフィールドに必要なのでこれが私の実装です:
シリアライザクラス:
public class CustomCalendarSerializer extends JsonSerializer<Calendar> {
public static final SimpleDateFormat FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm");
public static final Locale LOCALE_HUNGARIAN = new Locale("hu", "HU");
public static final TimeZone LOCAL_TIME_ZONE = TimeZone.getTimeZone("Europe/Budapest");
@Override
public void serialize(Calendar value, JsonGenerator gen, SerializerProvider arg2)
throws IOException, JsonProcessingException {
if (value == null) {
gen.writeNull();
} else {
gen.writeString(FORMATTER.format(value.getTime()));
}
}
}
デシリアライザクラス:
public class CustomCalendarDeserializer extends JsonDeserializer<Calendar> {
@Override
public Calendar deserialize(JsonParser jsonparser, DeserializationContext context)
throws IOException, JsonProcessingException {
String dateAsString = jsonparser.getText();
try {
Date date = CustomCalendarSerializer.FORMATTER.parse(dateAsString);
Calendar calendar = Calendar.getInstance(
CustomCalendarSerializer.LOCAL_TIME_ZONE,
CustomCalendarSerializer.LOCALE_HUNGARIAN
);
calendar.setTime(date);
return calendar;
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
}
上記のクラスのおよび使用方法
public class CalendarEntry {
@JsonSerialize(using = CustomCalendarSerializer.class)
@JsonDeserialize(using = CustomCalendarDeserializer.class)
private Calendar calendar;
// ... additional things ...
}
この実装を使用して、シリアライゼーションおよびデシリアライゼーションプロセスを連続して実行すると、Originの値が連続して発生します。
@JsonFormatアノテーションのみを使用して逆シリアル化すると異なる結果が得られます私はあなたがアノテーションパラメータで変更することができないものを内部のタイムゾーンのデフォルト設定のために考えます(Jacksonライブラリ2.5.3と2.6.3の私の経験でした)バージョンも)。
RFC3339
datetimeフォーマットのスプリングブートアプリケーションの完全な例
package bj.demo;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import Java.text.SimpleDateFormat;
/**
* Created by [email protected] at 2018/5/4 10:22
*/
@SpringBootApplication
public class BarApp implements ApplicationListener<ApplicationReadyEvent> {
public static void main(String[] args) {
SpringApplication.run(BarApp.class, args);
}
@Autowired
private ObjectMapper objectMapper;
@Override
public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX"));
}
}
@ miklov-krivenの非常に有益な回答を基にして、これら2つの追加の考慮点が誰かに役立つことを証明することを願っています。
(1)同じクラスの中で静的な内部クラスとしてシリアライザとデシリアライザを含めるのはいい考えだと思います。 NB、SimpleDateFormatのスレッドセーフのためにThreadLocalを使用します。
public class DateConverter {
private static final ThreadLocal<SimpleDateFormat> sdf =
ThreadLocal.<SimpleDateFormat>withInitial(
() -> {return new SimpleDateFormat("yyyy-MM-dd HH:mm a z");});
public static class Serialize extends JsonSerializer<Date> {
@Override
public void serialize(Date value, JsonGenerator jgen SerializerProvider provider) throws Exception {
if (value == null) {
jgen.writeNull();
}
else {
jgen.writeString(sdf.get().format(value));
}
}
}
public static class Deserialize extends JsonDeserializer<Date> {
@Overrride
public Date deserialize(JsonParser jp, DeserializationContext ctxt) throws Exception {
String dateAsString = jp.getText();
try {
if (Strings.isNullOrEmpty(dateAsString)) {
return null;
}
else {
return new Date(sdf.get().parse(dateAsString).getTime());
}
}
catch (ParseException pe) {
throw new RuntimeException(pe);
}
}
}
}
(2)個々のクラスメンバーごとに@JsonSerializeおよび@JsonDeserializeアノテーションを使用する代わりに、アプリケーションレベルでカスタムシリアル化を適用することでJacksonのデフォルトシリアル化をオーバーライドすることもできます。つまり、Date型のクラスメンバーはすべてJacksonによってシリアル化されます各フィールドに明示的な注釈を付けずにこのカスタムシリアル化を使用します。たとえばSpring Bootを使用している場合は、次のようにします。
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
public Module customModule() {
SimpleModule module = new SimpleModule();
module.addSerializer(Date.class, new DateConverter.Serialize());
module.addDeserializer(Date.class, new Dateconverter.Deserialize());
return module;
}
}
Java.sql.Dateのカスタム日付フォーマットの使用に問題がある場合は、これが最も簡単な解決策です。
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(Java.sql.Date.class, new DateSerializer());
mapper.registerModule(module);
(このような答えは私に多くのトラブルを救った: https://stackoverflow.com/a/35212795/3149048 )
JacksonはデフォルトでSqlDateSerializerをJava.sql.Dateに使用していますが、現在、このシリアライザはdateformatを考慮に入れていません。この問題を参照してください。 https://github.com/FasterXML/ jackson-databind/issues/1407 。回避策は、コード例に示すように、Java.sql.Dateに別のシリアライザを登録することです。
他の回答で説明されているようにSimpleDateFormat
を設定することは、私が想定しているJava.util.Date
に対してのみ有効であることを指摘したいと思います。しかしJava.sql.Date
の場合、フォーマッタは機能しません。私の場合、シリアル化する必要があるモデルでは実際にはフィールドがJava.utl.Date
であったが実際のオブジェクトがJava.sql.Date
になってしまったため、フォーマッターが機能しなかった理由はあまり明確ではありませんでした。これは可能です
public class Java.sql extends Java.util.Date
だからこれは実際に有効です
Java.util.Date date = new Java.sql.Date(1542381115815L);
そのため、Dateフィールドが正しくフォーマットされていない理由がわからない場合は、そのオブジェクトが本当にJava.util.Date
であることを確認してください。
ここで は、なぜJava.sql.Date
の扱いが追加されないのかも言及されています。
これはそれから変化を変えることになるでしょう、そして私はそれが保証されるとは思わない。私たちがゼロから始めたのなら、私はその変化に賛成するでしょうが、それほど多くはありません。
私のために働いています。 SpringBoot.
import com.alibaba.fastjson.annotation.JSONField;
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
出力:
{
"createTime": "2019-06-14 13:07:21"
}