Skip to content
This repository was archived by the owner on Jun 30, 2023. It is now read-only.

Commit f1e6cec

Browse files
authored
Merge pull request #11 from blueapron/fix-oneof-handling
Fix oneof handling
2 parents 4281d94 + 60a0fcb commit f1e6cec

File tree

3 files changed

+71
-18
lines changed

3 files changed

+71
-18
lines changed

pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<groupId>com.blueapron</groupId>
88
<artifactId>kafka-connect-protobuf-converter</artifactId>
99
<packaging>jar</packaging>
10-
<version>2.0.0</version>
10+
<version>2.0.1</version>
1111

1212
<properties>
1313
<protobuf.version>3.4.0</protobuf.version>

src/main/java/com/blueapron/connect/protobuf/ProtobufData.java

+20-12
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import com.google.protobuf.ByteString;
55
import com.google.protobuf.Descriptors;
6+
import com.google.protobuf.Descriptors.OneofDescriptor;
67
import com.google.protobuf.GeneratedMessageV3;
78
import com.google.protobuf.InvalidProtocolBufferException;
89
import com.google.protobuf.Message;
@@ -21,6 +22,7 @@
2122
import java.util.ArrayList;
2223
import java.util.Collection;
2324
import java.util.HashMap;
25+
import java.util.HashSet;
2426
import java.util.List;
2527
import java.util.Map;
2628
import com.google.protobuf.util.Timestamps;
@@ -81,12 +83,6 @@ private String getProtoFieldName(String descriptorForTypeName, String connectFie
8183
return connectProtoNameMap.get(getProtoMapKey(descriptorForTypeName, connectFieldName));
8284
}
8385

84-
private boolean isUnsetOneof(Descriptors.FieldDescriptor fieldDescriptor, Object value) {
85-
return fieldDescriptor.getContainingOneof() != null &&
86-
fieldDescriptor.getType() != MESSAGE &&
87-
fieldDescriptor.getDefaultValue().equals(value);
88-
}
89-
9086
ProtobufData(Class<? extends com.google.protobuf.GeneratedMessageV3> clazz, String legacyName) {
9187
this.legacyName = legacyName;
9288

@@ -225,6 +221,13 @@ private boolean isProtobufDate(Schema schema) {
225221
return Date.SCHEMA.name().equals(schema.name());
226222
}
227223

224+
private void setStructField(Schema schema, Message message, Struct result, Descriptors.FieldDescriptor fieldDescriptor) {
225+
final String fieldName = getConnectFieldName(fieldDescriptor);
226+
final Field field = schema.field(fieldName);
227+
Object obj = message.getField(fieldDescriptor);
228+
result.put(fieldName, toConnectData(field.schema(), obj));
229+
}
230+
228231
Object toConnectData(Schema schema, Object value) {
229232
try {
230233
if (isProtobufTimestamp(schema)) {
@@ -329,15 +332,20 @@ Object toConnectData(Schema schema, Object value) {
329332
}
330333

331334
final Struct result = new Struct(schema.schema());
335+
final Descriptors.Descriptor descriptor = message.getDescriptorForType();
332336

333-
for (Descriptors.FieldDescriptor fieldDescriptor : message.getDescriptorForType().getFields()) {
334-
final String fieldName = getConnectFieldName(fieldDescriptor);
335-
final Field field = schema.field(fieldName);
337+
for (OneofDescriptor oneOfDescriptor : descriptor.getOneofs()) {
338+
final Descriptors.FieldDescriptor fieldDescriptor = message.getOneofFieldDescriptor(oneOfDescriptor);
339+
setStructField(schema, message, result, fieldDescriptor);
340+
}
336341

337-
Object obj = message.getField(fieldDescriptor);
338-
if (!isUnsetOneof(fieldDescriptor, obj)) {
339-
result.put(fieldName, toConnectData(field.schema(), obj));
342+
for (Descriptors.FieldDescriptor fieldDescriptor : descriptor.getFields()) {
343+
Descriptors.OneofDescriptor oneOfDescriptor = fieldDescriptor.getContainingOneof();
344+
if (oneOfDescriptor != null) {
345+
continue;
340346
}
347+
348+
setStructField(schema, message, result, fieldDescriptor);
341349
}
342350

343351
converted = result;

src/test/java/com/blueapron/connect/protobuf/ProtobufDataTest.java

+50-5
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,14 @@ private Schema getExpectedNestedTestProtoSchemaIntUserId() {
8686
return getExpectedNestedTestProtoSchema();
8787
}
8888

89+
private SchemaBuilder getComplexTypeSchemaBuilder() {
90+
final SchemaBuilder complexTypeBuilder = SchemaBuilder.struct();
91+
complexTypeBuilder.field("one_id", SchemaBuilder.string().optional().build());
92+
complexTypeBuilder.field("other_id", SchemaBuilder.int32().optional().build());
93+
complexTypeBuilder.field("is_active", SchemaBuilder.bool().optional().build());
94+
return complexTypeBuilder;
95+
}
96+
8997
private Schema getExpectedNestedTestProtoSchema() {
9098
final SchemaBuilder builder = SchemaBuilder.struct();
9199
final SchemaBuilder userIdBuilder = SchemaBuilder.struct();
@@ -99,11 +107,7 @@ private Schema getExpectedNestedTestProtoSchema() {
99107
builder.field("experiments_active", SchemaBuilder.array(SchemaBuilder.string().optional().build()).optional().build());
100108
builder.field("updated_at", org.apache.kafka.connect.data.Timestamp.builder().optional().build());
101109
builder.field("status", SchemaBuilder.string().optional().build());
102-
final SchemaBuilder complexTypeBuilder = SchemaBuilder.struct();
103-
complexTypeBuilder.field("one_id", SchemaBuilder.string().optional().build());
104-
complexTypeBuilder.field("other_id", SchemaBuilder.int32().optional().build());
105-
complexTypeBuilder.field("is_active", SchemaBuilder.bool().optional().build());
106-
builder.field("complex_type", complexTypeBuilder.optional().build());
110+
builder.field("complex_type", getComplexTypeSchemaBuilder().optional().build());
107111
builder.field("map_type", SchemaBuilder.array(SchemaBuilder.struct().field("key", Schema.OPTIONAL_STRING_SCHEMA).field("value", Schema.OPTIONAL_STRING_SCHEMA).optional().build()).optional().build());
108112
return builder.build();
109113
}
@@ -161,6 +165,27 @@ private Struct getExpectedNestedTestProtoResultIntUserId() throws ParseException
161165
return result;
162166
}
163167

168+
private NestedTestProtoOuterClass.ComplexType createProtoDefaultOneOf() throws ParseException {
169+
NestedTestProtoOuterClass.ComplexType.Builder complexTypeBuilder = NestedTestProtoOuterClass.ComplexType.newBuilder();
170+
complexTypeBuilder.setOtherId(0);
171+
return complexTypeBuilder.build();
172+
}
173+
174+
private NestedTestProtoOuterClass.ComplexType createProtoMultipleSetOneOf() throws ParseException {
175+
NestedTestProtoOuterClass.ComplexType.Builder complexTypeBuilder = NestedTestProtoOuterClass.ComplexType.newBuilder();
176+
complexTypeBuilder.setOneId("asdf");
177+
complexTypeBuilder.setOtherId(0);
178+
return complexTypeBuilder.build();
179+
}
180+
181+
private Struct getExpectedComplexTypeProtoWithDefaultOneOf() {
182+
Schema schema = getComplexTypeSchemaBuilder().build();
183+
Struct result = new Struct(schema.schema());
184+
result.put("other_id", 0);
185+
result.put("is_active", false);
186+
return result;
187+
}
188+
164189
private void assertSchemasEqual(Schema expectedSchema, Schema actualSchema) {
165190
assertEquals(expectedSchema.type(), actualSchema.type());
166191
assertEquals(expectedSchema.isOptional(), actualSchema.isOptional());
@@ -196,6 +221,26 @@ public void testToConnectDataWithNestedProtobufMessageAndIntUserId() throws Pars
196221
assertEquals(new SchemaAndValue(getExpectedNestedTestProtoSchemaIntUserId(), getExpectedNestedTestProtoResultIntUserId()), result);
197222
}
198223

224+
@Test
225+
public void testToConnectDataDefaultOneOf() throws ParseException {
226+
Schema schema = getComplexTypeSchemaBuilder().build();
227+
NestedTestProtoOuterClass.ComplexType message = createProtoDefaultOneOf();
228+
ProtobufData protobufData = new ProtobufData(NestedTestProtoOuterClass.ComplexType.class, LEGACY_NAME);
229+
SchemaAndValue result = protobufData.toConnectData(message.toByteArray());
230+
assertSchemasEqual(schema, result.schema());
231+
assertEquals(new SchemaAndValue(schema, getExpectedComplexTypeProtoWithDefaultOneOf()), result);
232+
}
233+
234+
@Test
235+
public void testToConnectDataDefaultOneOfCannotHaveTwoOneOfsSet() throws ParseException {
236+
Schema schema = getComplexTypeSchemaBuilder().build();
237+
NestedTestProtoOuterClass.ComplexType message = createProtoMultipleSetOneOf();
238+
ProtobufData protobufData = new ProtobufData(NestedTestProtoOuterClass.ComplexType.class, LEGACY_NAME);
239+
SchemaAndValue result = protobufData.toConnectData(message.toByteArray());
240+
assertSchemasEqual(schema, result.schema());
241+
assertEquals(new SchemaAndValue(schema, getExpectedComplexTypeProtoWithDefaultOneOf()), result);
242+
}
243+
199244
// Data Conversion tests
200245
@Test
201246
public void testToConnectSupportsOptionalValues() {

0 commit comments

Comments
 (0)