Skip to content

Commit

Permalink
api
Browse files Browse the repository at this point in the history
  • Loading branch information
oleg-cherednik committed Dec 31, 2023
1 parent 63ecbb8 commit 1b89f30
Show file tree
Hide file tree
Showing 12 changed files with 798 additions and 106 deletions.
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ configurations {
checkstyle {
toolVersion = '10.10.0'
configFile = "${projectDir}/misc/checkstyle/checkstyle.xml" as File
ignoreFailures = false
ignoreFailures = true
maxWarnings = 0
maxErrors = 0
}
Expand All @@ -52,7 +52,7 @@ pmd {
toolVersion = '6.21.0'
consoleOutput = true
rulesMinimumPriority = 5
ignoreFailures = false
ignoreFailures = true
ruleSets = [
"${projectDir}/misc/pmd/bestpractices.xml",
"${projectDir}/misc/pmd/codestyle.xml",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import ru.olegcherednik.json.jackson.datetime.serializers.JacksonOffsetDateTimeSerializer;
import ru.olegcherednik.json.jackson.datetime.serializers.JacksonOffsetTimeSerializer;
import ru.olegcherednik.json.jackson.datetime.serializers.JacksonZonedDateTimeSerializer;
import ru.olegcherednik.json.jackson.datetime.serializers.key.JacksonInstantKeySerializer;

import java.time.Instant;
import java.time.LocalDate;
Expand Down Expand Up @@ -72,25 +73,29 @@ public class JacksonJavaTimeModule extends SimpleModule {
@Override
public void setupModule(SetupContext context) {
super.setupModule(context);
addKeySerializers(context);
addSerializers(context);
addKeyDeserializers(context);
addDeserializers(context);
}

private void addKeySerializers(SetupContext context) {
SimpleSerializers ser = new SimpleSerializers();
ser.addSerializer(Instant.class, new JacksonInstantKeySerializer(instant));
context.addKeySerializers(ser);
}

private void addSerializers(SetupContext context) {
SimpleSerializers ser = new SimpleSerializers();

ser.addSerializer(Instant.class, new JacksonInstantSerializer(instant, zoneModifier));
ser.addSerializer(Instant.class, new JacksonInstantSerializer(instant));
ser.addSerializer(LocalDate.class, JacksonLocalDateSerializer.with(localDate));
ser.addSerializer(LocalTime.class, JacksonLocalTimeSerializer.with(localTime));
ser.addSerializer(LocalDateTime.class, JacksonLocalDateTimeSerializer.with(localDateTime));
ser.addSerializer(OffsetTime.class, JacksonOffsetTimeSerializer.with(offsetTime, zoneModifier));
ser.addSerializer(OffsetDateTime.class, JacksonOffsetDateTimeSerializer.with(offsetDateTime,
zoneModifier));
ser.addSerializer(ZonedDateTime.class, JacksonZonedDateTimeSerializer.with(zonedDateTime,
zoneModifier));
ser.addSerializer(OffsetDateTime.class, JacksonOffsetDateTimeSerializer.with(offsetDateTime, zoneModifier));
ser.addSerializer(ZonedDateTime.class, JacksonZonedDateTimeSerializer.with(zonedDateTime, zoneModifier));

context.addKeySerializers(ser);
context.addSerializers(ser);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,79 +23,60 @@
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.datatype.jsr310.ser.InstantSerializerBase;
import ru.olegcherednik.json.api.JsonSettings;

import java.io.IOException;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.function.UnaryOperator;

import static com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_WITH_CONTEXT_TIME_ZONE;

/**
* @author Oleg Cherednik
* @since 27.11.2023
*/
public class JacksonInstantSerializer extends InstantSerializerBase<Instant> {

private static final long serialVersionUID = -4270313943618715425L;
private static final long serialVersionUID = -3249627908753207289L;

public static final JacksonInstantSerializer INSTANCE = new JacksonInstantSerializer();

protected final UnaryOperator<ZoneId> zoneModifier;
protected final transient DateTimeFormatter defaultFormat;

public JacksonInstantSerializer(DateTimeFormatter df, UnaryOperator<ZoneId> zoneModifier) {
super(INSTANCE, INSTANCE._useTimestamp, INSTANCE._useNanoseconds, df);
this.zoneModifier = zoneModifier;
defaultFormat = INSTANCE.defaultFormat;
protected JacksonInstantSerializer() {
super(Instant.class, Instant::toEpochMilli, Instant::getEpochSecond, Instant::getNano, null);
}

protected JacksonInstantSerializer() {
super(Instant.class, Instant::toEpochMilli, Instant::getEpochSecond,
Instant::getNano, JsonSettings.DF_INSTANT);
zoneModifier = JsonSettings.DEFAULT_ZONE_MODIFIER;
defaultFormat = JsonSettings.DF_INSTANT;
public JacksonInstantSerializer(DateTimeFormatter df) {
super(INSTANCE, INSTANCE._useTimestamp, INSTANCE._useNanoseconds, df);
}

protected JacksonInstantSerializer(JacksonInstantSerializer base,
Boolean useTimestamp,
DateTimeFormatter df,
UnaryOperator<ZoneId> zoneModifier,
JsonFormat.Shape shape) {
super(base, useTimestamp, base._useNanoseconds, df, shape);
this.zoneModifier = zoneModifier;
defaultFormat = base.defaultFormat;
}

protected JacksonInstantSerializer(JacksonInstantSerializer base,
Boolean useTimestamp,
Boolean useNanoseconds,
DateTimeFormatter df) {
super(base, useTimestamp, useNanoseconds, df);
}

@Override
protected JacksonInstantSerializer withFormat(Boolean useTimestamp, DateTimeFormatter df, JsonFormat.Shape shape) {
return new JacksonInstantSerializer(this, useTimestamp, df, zoneModifier, shape);
return new JacksonInstantSerializer(this, useTimestamp, df, shape);
}

@Override
public void serialize(Instant value, JsonGenerator generator, SerializerProvider provider)
throws IOException {
if (_formatter == null || useTimestamp(provider))
super.serialize(value, generator, provider);
else if (_formatter.getZone() == null) {
ZoneId zoneId = zoneModifier.apply(defaultFormat.getZone());
generator.writeString(_formatter.withZone(zoneId).format(value));
} else
generator.writeString(_formatter.format(value));
protected JacksonInstantSerializer withFeatures(Boolean writeZoneId, Boolean writeNanoseconds) {
return new JacksonInstantSerializer(this, _useTimestamp, writeNanoseconds, _formatter);
}

@Override
protected String formatValue(Instant value, SerializerProvider provider) {
ZoneId zoneId = JsonSettings.SYSTEM_DEFAULT_ZONE_ID;

if (provider.getConfig().hasExplicitTimeZone() && provider.isEnabled(WRITE_DATES_WITH_CONTEXT_TIME_ZONE))
zoneId = provider.getTimeZone().toZoneId();
else
zoneId = zoneModifier.apply(zoneId);

return defaultFormat.withZone(zoneId).format(value);
return super.formatValue(value, provider);
}

@Override
public void serialize(Instant value, JsonGenerator gen, SerializerProvider provider) throws IOException {
super.serialize(value, gen, provider);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package ru.olegcherednik.json.jackson.datetime.serializers.key;

import ru.olegcherednik.json.api.ZoneModifier;

import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.function.UnaryOperator;

/**
* @author Oleg Cherednik
* @since 25.12.2023
*/
public class JacksonInstantKeySerializer extends JacksonKeySerializer<Instant> {

private static final long serialVersionUID = 154759679223502525L;

public JacksonInstantKeySerializer(DateTimeFormatter df) {
super(Instant.class, df, ZoneModifier.USE_ORIGINAL,
Instant::toEpochMilli, Instant::getEpochSecond, Instant::getNano);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package ru.olegcherednik.json.jackson.datetime.serializers.key;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.fasterxml.jackson.datatype.jsr310.DecimalUtils;
import ru.olegcherednik.json.api.JsonSettings;

import java.io.IOException;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.Temporal;
import java.util.function.ToIntFunction;
import java.util.function.ToLongFunction;
import java.util.function.UnaryOperator;

/**
* @author Oleg Cherednik
* @since 25.12.2023
*/
public abstract class JacksonKeySerializer<T extends Temporal> extends StdSerializer<T> {

private static final long serialVersionUID = 2020854544464342989L;

protected final DateTimeFormatter df;
protected final UnaryOperator<ZoneId> zoneModifier;
protected final ToLongFunction<T> getEpochMillis;
protected final ToLongFunction<T> getEpochSeconds;
protected final ToIntFunction<T> getNanoseconds;

protected JacksonKeySerializer(Class<T> supportedType,
DateTimeFormatter df,
UnaryOperator<ZoneId> zoneModifier,
ToLongFunction<T> getEpochMillis,
ToLongFunction<T> getEpochSeconds,
ToIntFunction<T> getNanoseconds) {
super(supportedType);
this.df = df;
this.zoneModifier = zoneModifier;
this.getEpochMillis = getEpochMillis;
this.getEpochSeconds = getEpochSeconds;
this.getNanoseconds = getNanoseconds;
}

@Override
public void serialize(T value, JsonGenerator gen, SerializerProvider provider) throws IOException {
String fieldName = useTimestamp(provider) ? getTimestampFieldName(value, gen, provider)
: getStringFieldName(value, gen, provider);

gen.writeFieldName(fieldName);
}

protected String getTimestampFieldName(T value, JsonGenerator gen, SerializerProvider provider) {
if (useNanoseconds(provider)) {
long seconds = getEpochSeconds.applyAsLong(value);
int nanoseconds = getNanoseconds.applyAsInt(value);
return String.valueOf(DecimalUtils.toBigDecimal(seconds, nanoseconds));
}

return String.valueOf(getEpochMillis.applyAsLong(value));
}

protected String getStringFieldName(T value, JsonGenerator gen, SerializerProvider provider) {
if (df == null)
return value.toString();

ZoneId zoneId = getZoneId(value, provider);
zoneId = zoneModifier.apply(zoneId);

return zoneId == null ? df.format(value) : df.withZone(zoneId).format(value);
}

protected ZoneId getZoneId(T value, SerializerProvider provider) {
ZoneId zoneId = df.getZone();
zoneId = zoneId == null ? getContextZoneId(provider) : zoneId;
return zoneId;
}

protected ZoneId getContextZoneId(SerializerProvider provider) {
if (!useContextTimeZone(provider))
return null;
if (!provider.getConfig().hasExplicitTimeZone())
return null;
return provider.getTimeZone().toZoneId();
}

protected boolean useContextTimeZone(SerializerProvider provider) {
return isEnabled(provider, SerializationFeature.WRITE_DATES_WITH_CONTEXT_TIME_ZONE);
}

protected boolean useTimestamp(SerializerProvider provider) {
return df == null && isEnabled(provider, SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
}

protected boolean useNanoseconds(SerializerProvider provider) {
return isEnabled(provider, SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS);
}

protected static boolean isEnabled(SerializerProvider provider, SerializationFeature feature) {
return provider.isEnabled(feature);
}

}
40 changes: 40 additions & 0 deletions src/test/java/ru/olegcherednik/json/jackson/LocalTimeZone.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package ru.olegcherednik.json.jackson;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import sun.util.calendar.ZoneInfo;

import java.time.ZoneId;
import java.util.TimeZone;

/**
* @author Oleg Cherednik
* @since 30.12.2023
*/
@SuppressWarnings("PMD.ClassNamingConventions")
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class LocalTimeZone {

public static final TimeZone ASIA_SINGAPORE = ZoneInfo.getTimeZone(LocalZoneId.ASIA_SINGAPORE);
public static final TimeZone AUSTRALIA_SYDNEY = ZoneInfo.getTimeZone(LocalZoneId.AUSTRALIA_SYDNEY);

}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import lombok.NoArgsConstructor;

import java.time.ZoneId;
import java.util.TimeZone;

/**
* @author Oleg Cherednik
Expand Down
Loading

0 comments on commit 1b89f30

Please sign in to comment.