Skip to content

Commit

Permalink
JsonFormat compatibility for unconventionally named properties
Browse files Browse the repository at this point in the history
  • Loading branch information
gowa committed Feb 1, 2025
1 parent 6aeb0e0 commit a9fd641
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,19 @@
@SuppressWarnings("serial")
public class PropertyNamingStrategyWrapper {

private static final NamingBase SNAKE_TO_CAMEL = new SnakeToCamelNamingStrategy();
static final NamingBase SNAKE_TO_CAMEL = new SnakeToCamelNamingStrategy();

private final NamingBase delegate;

public PropertyNamingStrategyWrapper(
Class<? extends Message> messageType,
MapperConfig<?> mapperConfig
MapperConfig<?> mapperConfig,
ProtobufJacksonConfig protobufJacksonConfig
) {
if (mapperConfig.getPropertyNamingStrategy() instanceof NamingBase) {
this.delegate = (NamingBase) mapperConfig.getPropertyNamingStrategy();
} else {
this.delegate = SNAKE_TO_CAMEL;
this.delegate = protobufJacksonConfig.propertyNamingStrategy();
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,41 @@
package com.hubspot.jackson.datatype.protobuf;

import com.fasterxml.jackson.databind.PropertyNamingStrategies.NamingBase;
import com.google.protobuf.ExtensionRegistry;
import com.hubspot.jackson.datatype.protobuf.internal.PropertyNamingCache;

public class ProtobufJacksonConfig {

private static final ProtobufJacksonConfig DEFAULT_INSTANCE = ProtobufJacksonConfig
.builder()
.build();

public static class PropertyNamingStrategies {

public static final NamingBase SNAKE_TO_CAMEL =
PropertyNamingStrategyWrapper.SNAKE_TO_CAMEL;
public static final NamingBase JSON_FORMAT =
PropertyNamingCache.JsonFormatPropertyNamingStrategy.INSTANCE;
}

private final ExtensionRegistryWrapper extensionRegistry;
private final boolean acceptLiteralFieldnames;
private final boolean properUnsignedNumberSerialization;
private final boolean serializeLongsAsString;
private final NamingBase propertyNamingStrategy;

private ProtobufJacksonConfig(
ExtensionRegistryWrapper extensionRegistry,
boolean acceptLiteralFieldnames,
boolean properUnsignedNumberSerialization,
boolean serializeLongsAsString
boolean serializeLongsAsString,
NamingBase propertyNamingStrategy
) {
this.extensionRegistry = extensionRegistry;
this.acceptLiteralFieldnames = acceptLiteralFieldnames;
this.properUnsignedNumberSerialization = properUnsignedNumberSerialization;
this.serializeLongsAsString = serializeLongsAsString;
this.propertyNamingStrategy = propertyNamingStrategy;
}

public static ProtobufJacksonConfig getDefaultInstance() {
Expand All @@ -49,12 +62,17 @@ public boolean serializeLongsAsString() {
return serializeLongsAsString;
}

public NamingBase propertyNamingStrategy() {
return propertyNamingStrategy;
}

public static class Builder {

private ExtensionRegistryWrapper extensionRegistry = ExtensionRegistryWrapper.empty();
private boolean acceptLiteralFieldnames = false;
private boolean properUnsignedNumberSerialization = false;
private boolean serializeLongsAsString = false;
private NamingBase propertyNamingStrategy = PropertyNamingStrategies.SNAKE_TO_CAMEL;

private Builder() {}

Expand All @@ -71,6 +89,7 @@ public Builder useCanonicalSerialization() {
acceptLiteralFieldnames(true);
properUnsignedNumberSerialization(true);
serializeLongsAsString(true);
propertyNamingStrategy(PropertyNamingStrategies.JSON_FORMAT);
return this;
}

Expand All @@ -91,12 +110,21 @@ public Builder serializeLongsAsString(boolean serializeLongsAsString) {
return this;
}

public Builder propertyNamingStrategy(NamingBase propertyNamingStrategy) {
this.propertyNamingStrategy =
propertyNamingStrategy == null
? PropertyNamingStrategies.SNAKE_TO_CAMEL
: propertyNamingStrategy;
return this;
}

public ProtobufJacksonConfig build() {
return new ProtobufJacksonConfig(
extensionRegistry,
acceptLiteralFieldnames,
properUnsignedNumberSerialization,
serializeLongsAsString
serializeLongsAsString,
propertyNamingStrategy
);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ private Map<String, ExtensionInfo> buildExtensionLookup(
) {
PropertyNamingStrategyWrapper namingStrategy = new PropertyNamingStrategyWrapper(
messageType,
context.getConfig()
context.getConfig(),
config
);

Map<String, ExtensionInfo> extensionLookup = new HashMap<>();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.hubspot.jackson.datatype.protobuf.internal;

import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
import com.google.common.collect.ImmutableMap;
Expand All @@ -22,6 +23,20 @@ public class PropertyNamingCache {
private final Map<PropertyNamingStrategy, Function<FieldDescriptor, String>> serializationCache;
private final Map<PropertyNamingStrategy, Function<String, FieldDescriptor>> deserializationCache;

public static class JsonFormatPropertyNamingStrategy
extends PropertyNamingStrategies.NamingBase {

public static final JsonFormatPropertyNamingStrategy INSTANCE =
new JsonFormatPropertyNamingStrategy();

private JsonFormatPropertyNamingStrategy() {}

@Override
public String translate(String fieldName) {
return defaultJsonName(fieldName);
}
}

private PropertyNamingCache(
Descriptor descriptor,
Class<? extends Message> messageType,
Expand Down Expand Up @@ -86,7 +101,8 @@ private Function<FieldDescriptor, String> buildSerializationFunction(
) {
PropertyNamingStrategyWrapper namingStrategy = new PropertyNamingStrategyWrapper(
messageType,
mapperConfig
mapperConfig,
config
);

Map<FieldDescriptor, String> tempMap = new HashMap<>();
Expand All @@ -107,7 +123,8 @@ private Function<String, FieldDescriptor> buildDeserializationFunction(
) {
PropertyNamingStrategyWrapper namingStrategy = new PropertyNamingStrategyWrapper(
messageType,
mapperConfig
mapperConfig,
config
);

Map<String, FieldDescriptor> tempMap = new HashMap<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.hubspot.jackson.datatype.protobuf.util.ProtobufCreator;
import com.hubspot.jackson.datatype.protobuf.util.TestProtobuf.AllFields;
import com.hubspot.jackson.datatype.protobuf.util.TestProtobuf3.AllFieldsProto3;
import com.hubspot.jackson.datatype.protobuf.util.TestProtobuf3.UnconventionalProto3;
import java.io.IOException;
import org.junit.Test;

Expand Down Expand Up @@ -81,6 +82,39 @@ public void jsonFormatSerializesAndWeDeserializeProto3() throws IOException {
);
}

@Test
public void jsonFormatSerializesAndWeDeserializeUnconventionalProto3()
throws IOException {
repeat(
() -> {
UnconventionalProto3 original = ProtobufCreator.create(
UnconventionalProto3.class
);
String json = JsonFormat.printer().print(original);
UnconventionalProto3 parsed = MAPPER.readValue(json, UnconventionalProto3.class);
assertThat(parsed).isEqualTo(original);
},
1_000
);
}

@Test
public void weSerializeAndJsonFormatDeserializesUnconventionalProto3()
throws IOException {
repeat(
() -> {
UnconventionalProto3 original = ProtobufCreator.create(
UnconventionalProto3.class
);
String json = MAPPER.writeValueAsString(original);
UnconventionalProto3.Builder builder = UnconventionalProto3.newBuilder();
JsonFormat.parser().merge(json, builder);
assertThat(builder.build()).isEqualTo(original);
},
1_000
);
}

private interface Runnable {
void run() throws IOException;
}
Expand Down
10 changes: 10 additions & 0 deletions src/test/proto/test_proto3.proto
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,13 @@ message JsonNameProto3 {
string lower_underscore = 3 [json_name = "lower_underscore"];
string different_name = 4 [json_name = "surprise!"];
}

message UnconventionalProto3 {
string camelCase = 1;
string weird_UpperCamelCase = 2;
string weird_lowerCamelCase = 3;
string weird_1lowerCamelCase = 4;
string weird_2UpperCamelCase = 5;
string weird_3_lowerCamelCase = 6;
string weird_4_UpperCamelCase = 7;
}

0 comments on commit a9fd641

Please sign in to comment.