Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support custom serdes for builtin types #459

Merged
merged 2 commits into from May 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -0,0 +1,60 @@
package io.micronaut.serde.jackson

import io.micronaut.core.annotation.NonNull
import io.micronaut.core.annotation.Order
import io.micronaut.core.type.Argument
import io.micronaut.core.util.StringUtils
import io.micronaut.serde.Decoder
import io.micronaut.serde.Deserializer
import io.micronaut.serde.Encoder
import io.micronaut.serde.ObjectMapper
import io.micronaut.serde.Serde
import io.micronaut.serde.Serializer
import io.micronaut.serde.annotation.Serdeable
import io.micronaut.test.annotation.MockBean
import io.micronaut.test.extensions.spock.annotation.MicronautTest
import jakarta.inject.Inject
import spock.lang.Specification

@MicronautTest
class CustomStringSerdeSpec extends Specification {

@Inject ObjectMapper objectMapper

void "test custom string encoder"() {
expect:
objectMapper.writeValueAsString(new Test(name: "Fred")) == '{"name":"derF"}'
objectMapper.writeValueAsString(new Test(name: "")) == '{"name":null}'
objectMapper.writeValueAsString(new Test(name: " ")) == '{"name":null}'
objectMapper.readValue('{"name":"derF"}', Test).name == "Fred"

}

@Serdeable
static class Test {
String name
}

@MockBean
Serde<String> stringSerde() {
return new Serde<String>() {
@Override
String deserialize(@NonNull Decoder decoder, @NonNull Deserializer.DecoderContext context, @NonNull Argument<? super String> type) throws IOException {
if (decoder.decodeNull()) {
return null
} else {
return decoder.decodeString().reverse()
}
}

@Override
void serialize(@NonNull Encoder encoder, @NonNull Serializer.EncoderContext context, @NonNull Argument<? extends String> type, @NonNull String value) throws IOException {
if (StringUtils.isEmpty(value.trim())) {
encoder.encodeNull()
} else {
encoder.encodeString(value.reverse())
}
}
}
}
}
Expand Up @@ -180,8 +180,16 @@ private void registerPrimitiveSerdes() {
}

private void registerBuiltInSerdes() {
this.deserializerMap.put(new TypeKey(Argument.STRING),
(NullableDeserializer<String>) (decoder, decoderContext, type) -> decoder.decodeString());
if (!this.deserializerDefMap.containsKey(String.class)) {
TypeKey tk = new TypeKey(Argument.STRING);
this.deserializerMap.put(tk,
(NullableDeserializer<String>) (decoder, decoderContext, type) -> decoder.decodeString());
}
if (!this.deserializerDefMap.containsKey(CharSequence.class)) {
TypeKey tk = new TypeKey(Argument.of(CharSequence.class));
this.deserializerMap.put(tk,
(NullableDeserializer<CharSequence>) (decoder, decoderContext, type) -> decoder.decodeString());
}
Stream.of(
new IntegerSerde(),
new LongSerde(),
Expand Down Expand Up @@ -214,8 +222,12 @@ private void registerBuiltInSerdes() {
private void register(SerdeRegistrar<?> serdeRegistrar) {
for (Argument<?> type : serdeRegistrar.getTypes()) {
final TypeKey typeEntry = new TypeKey(type);
DefaultSerdeRegistry.this.deserializerMap.put(typeEntry, serdeRegistrar);
DefaultSerdeRegistry.this.serializerMap.put(typeEntry, serdeRegistrar);
if (!DefaultSerdeRegistry.this.deserializerMap.containsKey(typeEntry)) {
DefaultSerdeRegistry.this.deserializerMap.put(typeEntry, serdeRegistrar);
}
if (!DefaultSerdeRegistry.this.serializerMap.containsKey(typeEntry)) {
DefaultSerdeRegistry.this.serializerMap.put(typeEntry, serdeRegistrar);
}
}
}

Expand Down
Expand Up @@ -48,17 +48,6 @@
@Factory
public class CoreDeserializers {

/**
* Deserializes string types.
*
* @return The string deserializer
*/
@Singleton
@NonNull
protected Deserializer<String> stringDeserializer() {
return new StringDeserializer();
}

/**
* Deserializes array lists.
*
Expand Down Expand Up @@ -189,22 +178,6 @@ protected <V> Deserializer<Optional<V>> optionalDeserializer() {
return new OptionalDeserializer<>();
}

private static class StringDeserializer implements Deserializer<String> {

@Override
public String deserialize(Decoder decoder, DecoderContext decoderContext, Argument<? super String> type) throws IOException {
if (decoder.decodeNull()) {
return null;
}
return decoder.decodeString();
}

@Override
public boolean allowNull() {
return true;
}
}

private static class OptionalDeserializer<V> implements CustomizableDeserializer<Optional<V>> {

@Override
Expand Down
2 changes: 1 addition & 1 deletion settings.gradle.kts
Expand Up @@ -6,7 +6,7 @@ pluginManagement {
}

plugins {
id("io.micronaut.build.shared.settings") version "5.3.16"
id("io.micronaut.build.shared.settings") version "5.4.9"
}

enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
Expand Down