CAMEL-14192: Add toMap in the protobuf data format
diff --git a/components/camel-protobuf/src/main/java/org/apache/camel/dataformat/protobuf/ProtobufConverter.java b/components/camel-protobuf/src/main/java/org/apache/camel/dataformat/protobuf/ProtobufConverter.java
index a4d2acf..2a2a85a 100644
--- a/components/camel-protobuf/src/main/java/org/apache/camel/dataformat/protobuf/ProtobufConverter.java
+++ b/components/camel-protobuf/src/main/java/org/apache/camel/dataformat/protobuf/ProtobufConverter.java
@@ -16,9 +16,12 @@
*/
package org.apache.camel.dataformat.protobuf;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.stream.Collectors;
+import com.google.protobuf.Descriptors;
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.EnumValueDescriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
@@ -28,20 +31,9 @@
public final class ProtobufConverter {
- private final Message defaultInstance;
-
- private ProtobufConverter(final Message defaultInstance) {
- this.defaultInstance = defaultInstance;
- }
-
- public static ProtobufConverter create(final Message defaultInstance) {
- ObjectHelper.notNull(defaultInstance, "defaultInstance");
-
- return new ProtobufConverter(defaultInstance);
- }
-
- public Message toProto(final Map<?, ?> inputData) {
+ public static Message toProto(final Map<?, ?> inputData, final Message defaultInstance) {
ObjectHelper.notNull(inputData, "inputData");
+ ObjectHelper.notNull(defaultInstance, "defaultInstance");
final Descriptor descriptor = defaultInstance.getDescriptorForType();
final Builder target = defaultInstance.newBuilderForType();
@@ -49,7 +41,7 @@
return convertMapToMessage(descriptor, target, inputData);
}
- private Message convertMapToMessage(final Descriptor descriptor, final Builder builder, final Map<?, ?> inputData) {
+ private static Message convertMapToMessage(final Descriptor descriptor, final Builder builder, final Map<?, ?> inputData) {
ObjectHelper.notNull(descriptor, "descriptor");
ObjectHelper.notNull(builder, "builder");
ObjectHelper.notNull(inputData, "inputData");
@@ -70,7 +62,7 @@
return builder.build();
}
- private Object getSuitableFieldValue(final FieldDescriptor fieldDescriptor, final Builder builder, final Object inputValue) {
+ private static Object getSuitableFieldValue(final FieldDescriptor fieldDescriptor, final Builder builder, final Object inputValue) {
ObjectHelper.notNull(fieldDescriptor, "fieldDescriptor");
ObjectHelper.notNull(builder, "builder");
ObjectHelper.notNull(inputValue, "inputValue");
@@ -89,7 +81,7 @@
}
}
- private EnumValueDescriptor getEnumValue(final FieldDescriptor fieldDescriptor, final Object value) {
+ private static EnumValueDescriptor getEnumValue(final FieldDescriptor fieldDescriptor, final Object value) {
final EnumValueDescriptor enumValueDescriptor = getSuitableEnumValue(fieldDescriptor, value);
if (enumValueDescriptor == null) {
@@ -100,7 +92,7 @@
return enumValueDescriptor;
}
- private EnumValueDescriptor getSuitableEnumValue(final FieldDescriptor fieldDescriptor, final Object value) {
+ private static EnumValueDescriptor getSuitableEnumValue(final FieldDescriptor fieldDescriptor, final Object value) {
// we check if value is string, we find index by name, otherwise by integer
if (value instanceof String) {
return fieldDescriptor.getEnumType().findValueByName((String) value);
@@ -110,6 +102,53 @@
}
}
+ public static Map<String, Object> toMap(final Message inputProto) {
+ return convertProtoMessageToMap(inputProto);
+ }
+
+ private static Map<String, Object> convertProtoMessageToMap(final Message inputData) {
+ ObjectHelper.notNull(inputData, "inputData");
+
+ final Map<Descriptors.FieldDescriptor, Object> allFields = inputData.getAllFields();
+
+ final Map<String, Object> mapResult = new LinkedHashMap<>();
+
+ // we set our values from descriptors to map
+ allFields.forEach((fieldDescriptor, value) -> {
+ final String fieldName = fieldDescriptor.getName();
+ if (fieldDescriptor.isRepeated()) {
+ final List<?> repeatedValues = castValue(value, List.class, String.format("Not able to cast value to list, make sure you have a list for the repeated field '%s'", fieldName));
+ mapResult.put(fieldName, repeatedValues.stream().map(singleValue -> convertValueToSuitableFieldType(singleValue, fieldDescriptor)).collect(Collectors.toList()));
+ } else {
+ mapResult.put(fieldName, convertValueToSuitableFieldType(value, fieldDescriptor));
+ }
+ });
+
+ return mapResult;
+ }
+
+ private static Object convertValueToSuitableFieldType(final Object value, final Descriptors.FieldDescriptor fieldDescriptor) {
+ ObjectHelper.notNull(fieldDescriptor, "fieldDescriptor");
+ ObjectHelper.notNull(value, "value");
+
+ Object result;
+
+ switch (fieldDescriptor.getJavaType()) {
+ case ENUM:
+ case BYTE_STRING:
+ result = value.toString();
+ break;
+ case MESSAGE:
+ result = convertProtoMessageToMap((Message)value);
+ break;
+ default:
+ result = value;
+ break;
+ }
+
+ return result;
+ }
+
private static <T> T castValue(final Object value, final Class<T> type, final String errorMessage) {
try {
return type.cast(value);
diff --git a/components/camel-protobuf/src/main/java/org/apache/camel/dataformat/protobuf/ProtobufDataFormat.java b/components/camel-protobuf/src/main/java/org/apache/camel/dataformat/protobuf/ProtobufDataFormat.java
index b14b28e..ad8fe04 100644
--- a/components/camel-protobuf/src/main/java/org/apache/camel/dataformat/protobuf/ProtobufDataFormat.java
+++ b/components/camel-protobuf/src/main/java/org/apache/camel/dataformat/protobuf/ProtobufDataFormat.java
@@ -147,8 +147,8 @@
private Message convertGraphToMessage(final Exchange exchange, final Object inputData) throws NoTypeConversionAvailableException {
final Map<?, ?> messageInMap = exchange.getContext().getTypeConverter().tryConvertTo(Map.class, exchange, inputData);
if (messageInMap != null) {
- final ProtobufConverter protobufConverter = ProtobufConverter.create(defaultInstance);
- return protobufConverter.toProto(messageInMap);
+ //final ProtobufConverter protobufConverter = ProtobufConverter.create(defaultInstance);
+ return ProtobufConverter.toProto(messageInMap, defaultInstance);
}
return exchange.getContext().getTypeConverter().mandatoryConvertTo(Message.class, exchange, inputData);
}
diff --git a/components/camel-protobuf/src/main/java/org/apache/camel/dataformat/protobuf/ProtobufTypeConverter.java b/components/camel-protobuf/src/main/java/org/apache/camel/dataformat/protobuf/ProtobufTypeConverter.java
new file mode 100644
index 0000000..832ec20
--- /dev/null
+++ b/components/camel-protobuf/src/main/java/org/apache/camel/dataformat/protobuf/ProtobufTypeConverter.java
@@ -0,0 +1,15 @@
+package org.apache.camel.dataformat.protobuf;
+
+import java.util.Map;
+
+import com.google.protobuf.Message;
+import org.apache.camel.Converter;
+
+//@Converter(generateLoader = true)
+public class ProtobufTypeConverter {
+
+ //@Converter
+ public static Map<String, Object> toMap(final Message message) {
+ return ProtobufConverter.toMap(message);
+ }
+}
diff --git a/components/camel-protobuf/src/test/java/org/apache/camel/dataformat/protobuf/ProtobufConverterTest.java b/components/camel-protobuf/src/test/java/org/apache/camel/dataformat/protobuf/ProtobufConverterTest.java
index 94ac420..1af84df 100644
--- a/components/camel-protobuf/src/test/java/org/apache/camel/dataformat/protobuf/ProtobufConverterTest.java
+++ b/components/camel-protobuf/src/test/java/org/apache/camel/dataformat/protobuf/ProtobufConverterTest.java
@@ -51,8 +51,7 @@
input.put("nicknames", Arrays.asList("awesome1", "awesome2"));
input.put("address", address);
- final ProtobufConverter protobufConverter = ProtobufConverter.create(AddressBookProtos.Person.getDefaultInstance());
- final AddressBookProtos.Person message = (AddressBookProtos.Person) protobufConverter.toProto(input);
+ final AddressBookProtos.Person message = (AddressBookProtos.Person) ProtobufConverter.toProto(input, AddressBookProtos.Person.getDefaultInstance());
// assert primitives types and strings
assertEquals("Martin", message.getName());
@@ -82,8 +81,7 @@
input.put("id", 1234);
input.put("address", "wrong address");
- final ProtobufConverter protobufConverter = ProtobufConverter.create(AddressBookProtos.Person.getDefaultInstance());
- final AddressBookProtos.Person message = (AddressBookProtos.Person) protobufConverter.toProto(input);
+ final AddressBookProtos.Person message = (AddressBookProtos.Person) ProtobufConverter.toProto(input, AddressBookProtos.Person.getDefaultInstance());
}
@Test(expected = IllegalArgumentException.class)
@@ -94,8 +92,39 @@
input.put("id", 1234);
input.put("nicknames", "wrong nickname");
- final ProtobufConverter protobufConverter = ProtobufConverter.create(AddressBookProtos.Person.getDefaultInstance());
- final AddressBookProtos.Person message = (AddressBookProtos.Person) protobufConverter.toProto(input);
+ final AddressBookProtos.Person message = (AddressBookProtos.Person) ProtobufConverter.toProto(input, AddressBookProtos.Person.getDefaultInstance());
+ }
+
+ @Test
+ public void testIfItCorrectlyConvertMessageToMap() {
+ final Map<String, Object> phoneNumber = new HashMap<>();
+ phoneNumber.put("number", "011122233");
+ phoneNumber.put("type", "MOBILE");
+
+ final Map<String, Object> phoneNumber2 = new HashMap<>();
+ phoneNumber2.put("number", "5542454");
+ phoneNumber2.put("type", "WORK");
+
+ final Map<String, Object> address = new HashMap<>();
+ address.put("street", "awesome street");
+ address.put("street_number", 12);
+ address.put("is_valid", false);
+
+ final Map<String, Object> input = new HashMap<>();
+
+ input.put("name", "Martin");
+ input.put("id", 1234);
+ input.put("phone", Arrays.asList(phoneNumber, phoneNumber2));
+ input.put("email", "some@some.com");
+ input.put("nicknames", Arrays.asList("awesome1", "awesome2"));
+ input.put("address", address);
+
+ final AddressBookProtos.Person message = (AddressBookProtos.Person) ProtobufConverter.toProto(input, AddressBookProtos.Person.getDefaultInstance());
+
+ final Map<String, Object> resultedMessageMap = ProtobufConverter.toMap(message);
+
+ assertEquals(input, resultedMessageMap);
+
}
}
diff --git a/components/camel-protobuf/src/test/java/org/apache/camel/dataformat/protobuf/ProtobufMarshalAndUnmarshalMapTest.java b/components/camel-protobuf/src/test/java/org/apache/camel/dataformat/protobuf/ProtobufMarshalAndUnmarshalMapTest.java
index a4c4eb3..201a5d6 100644
--- a/components/camel-protobuf/src/test/java/org/apache/camel/dataformat/protobuf/ProtobufMarshalAndUnmarshalMapTest.java
+++ b/components/camel-protobuf/src/test/java/org/apache/camel/dataformat/protobuf/ProtobufMarshalAndUnmarshalMapTest.java
@@ -42,7 +42,7 @@
final Map<String, Object> input = new HashMap<>();
final Map<String, Object> phoneNumber = new HashMap<>();
phoneNumber.put("number", "011122233");
- phoneNumber.put("type", 0);
+ phoneNumber.put("type", "MOBILE");
input.put("name", "Martin");
input.put("id", 1234);
@@ -63,6 +63,9 @@
assertEquals(1234, output.getId());
assertEquals("011122233", output.getPhone(0).getNumber());
assertEquals(0, output.getPhone(0).getType().getNumber());
+
+ final Map resultedMap = mock.getReceivedExchanges().get(0).getMessage().getBody(Map.class);
+ assertEquals(input, resultedMap);
}
@Override