Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/2.12.x' into 2.13.x
Browse files Browse the repository at this point in the history
  • Loading branch information
graemerocher committed Jan 9, 2025
2 parents 86fe0e2 + 88d8b56 commit 278d4bb
Show file tree
Hide file tree
Showing 7 changed files with 323 additions and 13 deletions.
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ groovy = "4.0.22"
micronaut = "4.7.11"
micronaut-platform = "4.7.3"
micronaut-docs = "2.0.0"
micronaut-test = "4.6.0"
micronaut-test = "4.6.2"
micronaut-discovery = "4.5.0"
micronaut-logging = "1.5.1"
micronaut-oracle-cloud = "4.3.6"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
*/
package io.micronaut.serde.annotation;

import io.micronaut.context.annotation.AliasFor;
import io.micronaut.core.annotation.Introspected;
import io.micronaut.serde.Deserializer;
import io.micronaut.serde.Serializer;
Expand Down Expand Up @@ -48,13 +47,11 @@
/**
* @return Whether build time validation should fail compilation on definition errors.
*/
@AliasFor(annotation = SerdeConfig.class, member = SerdeConfig.VALIDATE)
boolean validate() default true;

/**
* @return Naming strategy to use for both serialization and deserialization.
*/
@AliasFor(annotation = SerdeConfig.class, member = SerdeConfig.NAMING)
Class<? extends PropertyNamingStrategy> naming() default IdentityStrategy.class;

/**
Expand All @@ -67,26 +64,22 @@
/**
* @return The {@link io.micronaut.serde.Serializer} to use.
*/
@AliasFor(annotation = SerdeConfig.class, member = SerdeConfig.SERIALIZER_CLASS)
Class<? extends Serializer> using() default Serializer.class;

/**
* @return Whether build time validation should fail compilation on definition errors.
*/
@AliasFor(annotation = SerdeConfig.class, member = SerdeConfig.VALIDATE)
boolean validate() default true;

/**
* Use the given class to serialize this type.
* @return A type that is a subclass of the annotated type.
*/
@AliasFor(annotation = SerdeConfig.class, member = SerdeConfig.SERIALIZE_AS)
Class<?> as() default void.class;

/**
* @return Naming strategy to use.
*/
@AliasFor(annotation = SerdeConfig.class, member = SerdeConfig.NAMING)
Class<? extends PropertyNamingStrategy> naming() default IdentityStrategy.class;
}

Expand All @@ -100,26 +93,22 @@
/**
* @return The deserializer.
*/
@AliasFor(annotation = SerdeConfig.class, member = SerdeConfig.DESERIALIZER_CLASS)
Class<? extends Deserializer> using() default Deserializer.class;

/**
* @return Whether build time validation should fail compilation on definition errors.
*/
@AliasFor(annotation = SerdeConfig.class, member = SerdeConfig.VALIDATE)
boolean validate() default true;

/**
* Use the given class to deserialize this type.
* @return A type that is a subclass of the annotated type.
*/
@AliasFor(annotation = SerdeConfig.class, member = SerdeConfig.DESERIALIZE_AS)
Class<?> as() default void.class;

/**
* @return Naming strategy to use.
*/
@AliasFor(annotation = SerdeConfig.class, member = SerdeConfig.NAMING)
Class<? extends PropertyNamingStrategy> naming() default IdentityStrategy.class;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -676,6 +676,7 @@ package custom;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.micronaut.context.annotation.Bean;
import io.micronaut.core.annotation.NonNull;
import io.micronaut.core.type.Argument;
import io.micronaut.serde.annotation.Serdeable;
Expand All @@ -697,7 +698,66 @@ record CustomValue(
}
}
@Singleton
@Bean(typed = CustomSerde.class)
class CustomSerde implements Deserializer<Integer> {
@Override
public Integer getDefaultValue(DecoderContext ignoredContext, Argument<? super Integer> ignoredType) {
return -2;
}
@Override
public Integer deserialize(Decoder decoder, DecoderContext context, Argument<? super Integer> type) throws IOException {
return decoder.decodeInt();
}
@Override
public Integer deserializeNullable(Decoder decoder, DecoderContext context, Argument<? super Integer> type) throws IOException {
if (decoder.decodeNull()) {
return -1;
}
return decoder.decodeInt();
}
}
''')

expect:
jsonMapper.readValue('{"value":1}', typeUnderTest).value() == 1
jsonMapper.readValue('{"value":null}', typeUnderTest).value() == -1
jsonMapper.readValue('{}', typeUnderTest).value() == -2

cleanup:
context.close()
}
void "test custom deserializer 2"() {

given:
def context = buildContext('custom.CustomValue','''
package custom;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.micronaut.context.annotation.Bean;
import io.micronaut.core.annotation.NonNull;
import io.micronaut.core.type.Argument;
import io.micronaut.serde.annotation.Serdeable;
import io.micronaut.serde.annotation.SerdeImport;
import io.micronaut.serde.Decoder;
import io.micronaut.serde.Deserializer;
import jakarta.inject.Singleton;
import java.io.IOException;
@Serdeable
record CustomValue(
@Serdeable.Deserializable(using = CustomSerde.class)
@NonNull
Integer value
) {
@JsonCreator
public CustomValue {
}
}
@Bean(typed = CustomSerde.class)
class CustomSerde implements Deserializer<Integer> {
@Override
public Integer getDefaultValue(DecoderContext ignoredContext, Argument<? super Integer> ignoredType) {
Expand Down Expand Up @@ -727,4 +787,99 @@ class CustomSerde implements Deserializer<Integer> {
cleanup:
context.close()
}

void "test custom serializer"() {
given:
def context = buildContext('custom.CustomValue','''
package custom;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.micronaut.context.annotation.Bean;
import io.micronaut.core.annotation.NonNull;
import io.micronaut.core.type.Argument;
import io.micronaut.serde.Encoder;
import io.micronaut.serde.Serializer;
import io.micronaut.serde.annotation.Serdeable;
import io.micronaut.serde.annotation.SerdeImport;
import io.micronaut.serde.Decoder;
import jakarta.inject.Singleton;
import java.io.IOException;
@Serdeable
record CustomValue(
@Serdeable.Serializable(using = CustomSerde.class)
@JsonProperty("value")
@NonNull
Integer value
) {
@JsonCreator
public CustomValue {
}
}
@Bean(typed = CustomSerde.class)
class CustomSerde implements Serializer<Integer> {
@Override
public void serialize(Encoder encoder, EncoderContext context, Argument<? extends Integer> type, Integer value) throws IOException {
encoder.encodeInt(123);
}
}
''')

expect:
jsonMapper.writeValueAsString(typeUnderTest.type.newInstance(1)) == """{"value":123}"""
jsonMapper.writeValueAsString(typeUnderTest.type.newInstance(2)) == """{"value":123}"""
jsonMapper.writeValueAsString(typeUnderTest.type.newInstance(3)) == """{"value":123}"""

cleanup:
context.close()
}

void "test custom serializer 2"() {
given:
def context = buildContext('custom.CustomValue','''
package custom;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.micronaut.context.annotation.Bean;
import io.micronaut.core.annotation.NonNull;
import io.micronaut.core.type.Argument;
import io.micronaut.serde.Encoder;
import io.micronaut.serde.Serializer;
import io.micronaut.serde.annotation.Serdeable;
import io.micronaut.serde.annotation.SerdeImport;
import io.micronaut.serde.Decoder;
import jakarta.inject.Singleton;
import java.io.IOException;
@Serdeable
record CustomValue(
@Serdeable.Serializable(using = CustomSerde.class)
@NonNull
Integer value
) {
@JsonCreator
public CustomValue {
}
}
@Bean(typed = CustomSerde.class)
class CustomSerde implements Serializer<Integer> {
@Override
public void serialize(Encoder encoder, EncoderContext context, Argument<? extends Integer> type, Integer value) throws IOException {
encoder.encodeInt(123);
}
}
''')

expect:
jsonMapper.writeValueAsString(typeUnderTest.type.newInstance(1)) == """{"value":123}"""
jsonMapper.writeValueAsString(typeUnderTest.type.newInstance(2)) == """{"value":123}"""
jsonMapper.writeValueAsString(typeUnderTest.type.newInstance(3)) == """{"value":123}"""

cleanup:
context.close()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright 2017-2025 original authors
*
* Licensed 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
*
* https://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 io.micronaut.serde.processor.serde;

import io.micronaut.core.annotation.AnnotationValue;
import io.micronaut.core.annotation.AnnotationValueBuilder;
import io.micronaut.inject.annotation.TypedAnnotationMapper;
import io.micronaut.inject.visitor.VisitorContext;
import io.micronaut.serde.annotation.Serdeable;
import io.micronaut.serde.config.annotation.SerdeConfig;
import java.util.List;

public final class DeserializableMapper
implements TypedAnnotationMapper<Serdeable.Deserializable> {
@Override
public Class<Serdeable.Deserializable> annotationType() {
return Serdeable.Deserializable.class;
}

@Override
public List<AnnotationValue<?>> map(AnnotationValue<Serdeable.Deserializable> annotation, VisitorContext visitorContext) {
AnnotationValueBuilder<SerdeConfig> builder = AnnotationValue.builder(SerdeConfig.class);
annotation.annotationClassValue("as").ifPresent(as ->
builder
.member(SerdeConfig.DESERIALIZE_AS, as)
);
annotation.annotationClassValue("using").ifPresent(using ->
builder
.member(SerdeConfig.DESERIALIZER_CLASS, using)
);
annotation.booleanValue("validate").ifPresent(validation ->
builder
.member(SerdeConfig.VALIDATE, validation)
);
annotation.annotationClassValue("naming").ifPresent(naming ->
builder
.member(SerdeConfig.NAMING, naming)
);

return List.of(builder.build());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright 2017-2025 original authors
*
* Licensed 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
*
* https://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 io.micronaut.serde.processor.serde;

import io.micronaut.core.annotation.AnnotationValue;
import io.micronaut.core.annotation.AnnotationValueBuilder;
import io.micronaut.inject.annotation.TypedAnnotationMapper;
import io.micronaut.inject.visitor.VisitorContext;
import io.micronaut.serde.annotation.Serdeable;
import io.micronaut.serde.config.annotation.SerdeConfig;
import java.util.List;

public final class SerdeableMapper
implements TypedAnnotationMapper<Serdeable> {
@Override
public Class<Serdeable> annotationType() {
return Serdeable.class;
}

@Override
public List<AnnotationValue<?>> map(AnnotationValue<Serdeable> annotation, VisitorContext visitorContext) {

AnnotationValueBuilder<SerdeConfig> builder = AnnotationValue.builder(SerdeConfig.class);
annotation.booleanValue("validate").ifPresent(validation ->
builder
.member(SerdeConfig.VALIDATE, validation)
);
annotation.annotationClassValue("naming").ifPresent(naming ->
builder
.member(SerdeConfig.NAMING, naming)
);

AnnotationValue<SerdeConfig> result = builder.build();
if (!result.getValues().isEmpty()) {
return List.of(result);
} else {
return List.of();
}
}
}
Loading

0 comments on commit 278d4bb

Please sign in to comment.