179

私は次のようなAPIからの日付形式を持っています:

"start_time": "2015-10-1 3:00 PM GMT+1:00"

これはYYYY-DD-MMHH:MM am /pmGMTタイムスタンプです。この値をPOJOのDate変数にマッピングしています。明らかに、その表示変換エラー。

私は2つのことを知りたいです:

  1. ジャクソンで変換を実行するために使用する必要があるフォーマットは何ですか?日付はこれに適したフィールドタイプですか?
  2. 一般に、Jacksonによってオブジェクトメンバーにマップされる前に変数を処理する方法はありますか?フォーマットの変更、計算など。
4

9 に答える 9

382

Jackson v2.0以降、オブジェクトメンバーで直接@JsonFormatアノテーションを使用できます。

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm a z")
private Date date;
于 2014-11-24T10:02:04.440 に答える
148

ジャクソンで変換を実行するために使用する必要があるフォーマットは何ですか?日付はこれに適したフィールドタイプですか?

Dateこのためのファインフィールドタイプです。以下を使用して、JSONを非常に簡単に解析可能にすることができますObjectMapper.setDateFormat

DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm a z");
myObjectMapper.setDateFormat(df);

一般に、Jacksonによってオブジェクトメンバーにマップされる前に変数を処理する方法はありますか?フォーマットの変更、計算など。

はい。カスタムの実装を含むいくつかのオプションがあります。JsonDeserializerたとえば、を拡張しJsonDeserializer<Date>ます。これは良いスタートです。

于 2012-09-17T16:45:10.550 に答える
59

もちろん、シリアル化と逆シリアル化と呼ばれる自動化された方法があり、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

日付フィールドの例がありますが、カレンダーフィールドが必要だったので、ここに私の実装があります

シリアライザークラス:

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 ...
}

この実装を使用すると、シリアル化および逆シリアル化プロセスを連続して実行すると、元の値が生成されます。

@JsonFormatアノテーションを使用するだけで、逆シリアル化によって異なる結果が得られると思います。これは、ライブラリの内部タイムゾーンのデフォルト設定のため、アノテーションパラメータで変更できないものです(これは、Jacksonライブラリ2.5.3および2.6.3バージョンでの私の経験でもあります)。

于 2015-12-12T07:48:55.510 に答える
11

日付にTやZなどの文字を追加するには

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'")
private Date currentTime;

出力

{
    "currentTime": "2019-12-11T11:40:49Z"
}
于 2019-12-11T12:02:01.603 に答える
6

日時形式のスプリングブートアプリケーションの完全な例RFC3339

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 BaiJiFeiLong@gmail.com 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"));
    }
}
于 2018-05-04T11:35:50.610 に答える
4

@ miklov-krivenの非常に役立つ回答に基づいて、次の2つの追加の考慮事項が誰かに役立つことを願っています。

(1)同じクラスの静的内部クラスとしてシリアライザーとデシリアライザーを含めるのは良い考えだと思います。注意: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を使用している場合、これを行う1つの方法は次のようになります。

@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;
    }
}
于 2016-04-16T10:43:19.547 に答える
3

私のために働いています。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"
}
于 2019-06-15T09:05:43.270 に答える
2

java.sql.Dateのカスタム日付形式の使用に問題がある場合は、これが最も簡単な解決策です。

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(java.sql.Date.class, new DateSerializer());
mapper.registerModule(module);

(このSO-answerは私に多くのトラブルを救いました:https ://stackoverflow.com/a/35212795/3149048 )

Jacksonはデフォルトでjava.sql.DateにSqlDateSerializerを使用しますが、現在、このシリアライザーは日付形式を考慮していません。この問題を参照してください:https ://github.com/FasterXML/jackson-databind/issues/1407 。回避策は、コード例に示すように、java.sql.Dateに別のシリアライザーを登録することです。

于 2017-06-15T07:27:17.493 に答える
2

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);

したがって、日付フィールドが正しくフォーマットされていない理由がわからない場合は、オブジェクトが実際に。であることを確認してjava.util.Dateください。

java.sql.Dateまた、処理が追加されない理由についても説明します。

これは変化を壊すことになります、そして私はそれが正当化されるとは思いません。ゼロから始めた場合、私は変更に同意しますが、物事はそれほど多くはありません。

于 2018-11-16T16:00:09.143 に答える