Skip to content

Commit

Permalink
Merge branch '2.17'
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Jan 24, 2024
2 parents ffac28a + b4b0968 commit 03a059e
Show file tree
Hide file tree
Showing 10 changed files with 494 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package com.fasterxml.jackson.datatype.jdk8;

import java.util.Optional;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.util.StdConverter;

// [modules-java#294]: Optional + converters
public class OptionalConverterTest extends ModuleTestBase
{
static class Point
{
public int x, y;

protected Point() { }
public Point(int v1, int v2) {
x = v1;
y = v2;
}
}

static class PointDeserConverter extends StdConverter<int[], Point>
{
@Override
public Point convert(int[] value) {
return new Point(value[0], value[1]);
}
}

static class PointSerConverter extends StdConverter<Point, int[]>
{
@Override public int[] convert(Point value) {
return new int[] { value.x, value.y };
}
}

static class PointReferenceBean {
@JsonDeserialize(contentConverter=PointDeserConverter.class)
@JsonSerialize(contentConverter=PointSerConverter.class)
public Optional<Point> opt;

protected PointReferenceBean() { }
public PointReferenceBean(int x, int y) {
opt = Optional.of(new Point(x, y));
}
}

/*
/**********************************************************
/* Test methods
/**********************************************************
*/

private final ObjectMapper MAPPER = mapperWithModule();

// [modules-java#294]: Optional + converters, deser
public void testDeserializeOptionalConverting() throws Exception {
PointReferenceBean w = MAPPER.readerFor(PointReferenceBean.class)
.readValue("{\"opt\": [1,2]}");
assertNotNull(w);
assertNotNull(w.opt);
Point p = w.opt.get();
assertNotNull(p);
assertEquals(1, p.x);
assertEquals(2, p.y);
}

// [modules-java#294]: Optional + converters, ser
public void testSerializeOptionalConverting() throws Exception {
assertEquals("{\"opt\":[3,4]}",
MAPPER.writeValueAsString(new PointReferenceBean(3, 4)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,16 @@ public enum JavaTimeFeature implements JacksonFeature
* stringified numbers are always accepted as timestamps regardless of
* this feature.
*/
ALWAYS_ALLOW_STRINGIFIED_DATE_TIMESTAMPS(false)
ALWAYS_ALLOW_STRINGIFIED_DATE_TIMESTAMPS(false),

/**
* Feature that determines whether {@link java.time.Month} is serialized
* and deserialized as using a zero-based index (FALSE) or a one-based index (TRUE).
* For example, "1" would be serialized/deserialized as Month.JANUARY if TRUE and Month.FEBRUARY if FALSE.
*<p>
* Default setting is false, meaning that Month is serialized/deserialized as a zero-based index.
*/
ONE_BASED_MONTHS(false)
;

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package tools.jackson.datatype.jsr310.deser;

import java.time.Month;

import tools.jackson.databind.*;
import tools.jackson.databind.deser.ValueDeserializerModifier;

/**
* @since 2.17
*/
public class JavaTimeDeserializerModifier extends ValueDeserializerModifier {
private static final long serialVersionUID = 1L;

private final boolean _oneBaseMonths;

public JavaTimeDeserializerModifier(boolean oneBaseMonths) {
_oneBaseMonths = oneBaseMonths;
}

@Override
public ValueDeserializer<?> modifyEnumDeserializer(DeserializationConfig config, JavaType type,
BeanDescription beanDesc, ValueDeserializer<?> defaultDeserializer) {
if (_oneBaseMonths && type.hasRawClass(Month.class)) {
return new OneBasedMonthDeserializer(defaultDeserializer);
}
return defaultDeserializer;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package tools.jackson.datatype.jsr310.deser;

import java.time.Month;
import java.util.regex.Pattern;

import tools.jackson.core.JsonParser;
import tools.jackson.core.JsonToken;

import tools.jackson.databind.*;
import tools.jackson.databind.deser.std.DelegatingDeserializer;
import tools.jackson.databind.exc.InvalidFormatException;

/**
* @since 2.17
*/
public class OneBasedMonthDeserializer extends DelegatingDeserializer {
private static final Pattern HAS_ONE_OR_TWO_DIGITS = Pattern.compile("^\\d{1,2}$");

public OneBasedMonthDeserializer(ValueDeserializer<?> defaultDeserializer) {
super(defaultDeserializer);
}

@Override
public Object deserialize(JsonParser parser, DeserializationContext context) {
JsonToken token = parser.currentToken();
Month zeroBaseMonth = (Month) getDelegatee().deserialize(parser, context);
if (!_isNumericValue(parser.getText(), token)) {
return zeroBaseMonth;
}
if (zeroBaseMonth == Month.JANUARY) {
throw new InvalidFormatException(parser, "Month.JANUARY value not allowed for 1-based Month.", zeroBaseMonth, Month.class);
}
return zeroBaseMonth.minus(1);
}

private boolean _isNumericValue(String text, JsonToken token) {
return token == JsonToken.VALUE_NUMBER_INT || _isNumberAsString(text, token);
}

private boolean _isNumberAsString(String text, JsonToken token) {
return token == JsonToken.VALUE_STRING && HAS_ONE_OR_TWO_DIGITS.matcher(text).matches();
}

@Override
protected ValueDeserializer<?> newDelegatingInstance(ValueDeserializer<?> newDelegatee) {
return new OneBasedMonthDeserializer(newDelegatee);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package tools.jackson.datatype.jsr310.ser;

import java.time.Month;

import tools.jackson.databind.*;
import tools.jackson.databind.ser.ValueSerializerModifier;

/**
* @since 2.17
*/
public class JavaTimeSerializerModifier extends ValueSerializerModifier {
private static final long serialVersionUID = 1L;

private final boolean _oneBaseMonths;

public JavaTimeSerializerModifier(boolean oneBaseMonths) {
_oneBaseMonths = oneBaseMonths;
}

@Override
public ValueSerializer<?> modifyEnumSerializer(SerializationConfig config, JavaType valueType,
BeanDescription beanDesc, ValueSerializer<?> serializer) {
if (_oneBaseMonths && valueType.hasRawClass(Month.class)) {
return new OneBasedMonthSerializer(serializer);
}
return serializer;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package tools.jackson.datatype.jsr310.ser;

import java.time.Month;

import tools.jackson.core.JsonGenerator;

import tools.jackson.databind.*;

/**
* @since 2.17
*/
public class OneBasedMonthSerializer extends ValueSerializer<Month> {
private final ValueSerializer<Object> _defaultSerializer;

@SuppressWarnings("unchecked")
public OneBasedMonthSerializer(ValueSerializer<?> defaultSerializer)
{
_defaultSerializer = (ValueSerializer<Object>) defaultSerializer;
}

@Override
public void serialize(Month value, JsonGenerator gen, SerializerProvider ctxt)
{
// 15-Jan-2024, tatu: [modules-java8#274] This is not really sufficient
// (see `jackson-databind` `EnumSerializer` for full logic), but has to
// do for now. May need to add `@JsonFormat.shape` handling in future.
if (ctxt.isEnabled(SerializationFeature.WRITE_ENUMS_USING_INDEX)) {
gen.writeNumber(value.ordinal() + 1);
return;
}
_defaultSerializer.serialize(value, gen, ctxt);
}
}
Loading

0 comments on commit 03a059e

Please sign in to comment.