From ccb55b06b7953b82cc761c6fadd0b8936a4816df Mon Sep 17 00:00:00 2001 From: Adonis Charalambidis Date: Fri, 31 Aug 2018 12:42:42 +0300 Subject: [PATCH] [ISSUE: 696] fixes nested proto3 messages ClassNotFoundException (#697) * fixes nested proto3 messages ClassNotFoundException * proto3 msg container names in reverse order. * missing license header --- .../dozermapper/protobuf/util/ProtoUtils.java | 25 +++++--- .../ProtoBeansMultipleFilesMappingTest.java | 37 ++++++++++++ .../vo/proto/TestContainerObject.java | 60 +++++++++++++++++++ .../proto/ProtoTestObjectsMultipleFiles.proto | 15 +++++ .../resources/mappings/protoBeansMapping.xml | 22 +++++++ 5 files changed, 152 insertions(+), 7 deletions(-) create mode 100644 dozer-integrations/dozer-proto3/src/test/java/com/github/dozermapper/protobuf/vo/proto/TestContainerObject.java diff --git a/dozer-integrations/dozer-proto3/src/main/java/com/github/dozermapper/protobuf/util/ProtoUtils.java b/dozer-integrations/dozer-proto3/src/main/java/com/github/dozermapper/protobuf/util/ProtoUtils.java index 47cb5010b..eefcb7ae1 100644 --- a/dozer-integrations/dozer-proto3/src/main/java/com/github/dozermapper/protobuf/util/ProtoUtils.java +++ b/dozer-integrations/dozer-proto3/src/main/java/com/github/dozermapper/protobuf/util/ProtoUtils.java @@ -19,6 +19,7 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; +import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -27,7 +28,7 @@ import com.github.dozermapper.core.util.MappingUtils; import com.google.common.base.CaseFormat; import com.google.protobuf.ByteString; -import com.google.protobuf.DescriptorProtos; +import com.google.protobuf.DescriptorProtos.FileOptions; import com.google.protobuf.Descriptors; import com.google.protobuf.Message; import com.google.protobuf.ProtocolMessageEnum; @@ -207,23 +208,33 @@ private static Class getJavaClassIgnoreRepeated(final Descriptors.FieldDescri return getEnumClassByEnumDescriptor(descriptor.getEnumType(), beanContainer); case MESSAGE: return MappingUtils.loadClass(StringUtils.join( - getFullyQualifiedClassName(descriptor.getMessageType().getFile().getOptions(), descriptor.getMessageType().getName()), '.'), beanContainer); + getFullyQualifiedClassName(descriptor.getMessageType().getContainingType(), + descriptor.getMessageType().getFile().getOptions(), + descriptor.getMessageType().getName()), '.'), beanContainer); default: throw new MappingException("Unable to find " + descriptor.getJavaType()); } } - private static String[] getFullyQualifiedClassName(DescriptorProtos.FileOptions options, String name) { - if (options.getJavaMultipleFiles()) { - return new String[] {options.getJavaPackage(), name}; + private static String[] getFullyQualifiedClassName(Descriptors.Descriptor container, final FileOptions fileOpts, String name) { + + if (fileOpts.getJavaMultipleFiles()) { + LinkedList fqnSegments = new LinkedList<>(); + fqnSegments.push(name); + while (container != null) { + fqnSegments.push(container.getName()); + container = container.getContainingType(); + } + fqnSegments.push(fileOpts.getJavaPackage()); + return fqnSegments.toArray(new String[] {}); } - return new String[] {options.getJavaPackage(), options.getJavaOuterClassname(), name}; + return new String[] {fileOpts.getJavaPackage(), fileOpts.getJavaOuterClassname(), name}; } @SuppressWarnings("unchecked") private static Class getEnumClassByEnumDescriptor(Descriptors.EnumDescriptor descriptor, BeanContainer beanContainer) { - String name = StringUtils.join(getFullyQualifiedClassName(descriptor.getFile().getOptions(), descriptor.getName()), '.'); + String name = StringUtils.join(getFullyQualifiedClassName(descriptor.getContainingType(), descriptor.getFile().getOptions(), descriptor.getName()), '.'); return (Class)MappingUtils.loadClass(name, beanContainer); } diff --git a/dozer-integrations/dozer-proto3/src/test/java/com/github/dozermapper/protobuf/functional_tests/ProtoBeansMultipleFilesMappingTest.java b/dozer-integrations/dozer-proto3/src/test/java/com/github/dozermapper/protobuf/functional_tests/ProtoBeansMultipleFilesMappingTest.java index 49c01491c..ff201f28c 100644 --- a/dozer-integrations/dozer-proto3/src/test/java/com/github/dozermapper/protobuf/functional_tests/ProtoBeansMultipleFilesMappingTest.java +++ b/dozer-integrations/dozer-proto3/src/test/java/com/github/dozermapper/protobuf/functional_tests/ProtoBeansMultipleFilesMappingTest.java @@ -17,8 +17,12 @@ import com.github.dozermapper.core.DozerBeanMapperBuilder; import com.github.dozermapper.core.Mapper; +import com.github.dozermapper.protobuf.vo.proto.TestContainerObject; import com.github.dozermapper.protobuf.vo.proto.NestedObject; import com.github.dozermapper.protobuf.vo.proto.TestObject; +import com.github.dozermapper.protobuf.vo.proto.TestContainerObject.TestContainedEnum; +import com.github.dozermapper.protobuf.vo.protomultiple.ContainerObject; +import com.github.dozermapper.protobuf.vo.protomultiple.ContainerObject.ContainedEnum; import com.github.dozermapper.protobuf.vo.protomultiple.SimpleProtoTestObject; import org.junit.BeforeClass; @@ -68,4 +72,37 @@ public void canSimpleFromProto() { assertNotNull(result.getNested().getOne()); assertEquals(simpleProtoTestObject.getNested().getOne(), result.getNested().getOne()); } + + @Test + public void canNestedObjectToProto() { + TestContainerObject containerObject = new TestContainerObject(); + containerObject.setEnum1(TestContainedEnum.VALUE2); + containerObject.setObj1(new TestContainerObject.TestContainedObject()); + containerObject.getObj1().setC1("ABC"); + + ContainerObject result = mapper.map(containerObject, ContainerObject.class); + assertNotNull(result); + assertNotNull(result.getEnum1()); + assertNotNull(result.getObj1()); + assertNotNull(result.getObj1().getC1()); + assertEquals(containerObject.getObj1().getC1(), result.getObj1().getC1()); + assertEquals(containerObject.getEnum1().name(), result.getEnum1().name()); + } + + @Test + public void canNestedObjectFromProto() { + ContainerObject.Builder containerBuiler = ContainerObject.newBuilder(); + containerBuiler.setEnum1(ContainedEnum.VALUE2); + containerBuiler.setObj1(ContainerObject.ContainedObject.newBuilder().setC1("ABC").build()); + ContainerObject container = containerBuiler.build(); + TestContainerObject result = mapper.map(container, TestContainerObject.class); + assertNotNull(result); + assertNotNull(result.getEnum1()); + assertNotNull(result.getObj1()); + assertNotNull(result.getObj1().getC1()); + assertEquals(container.getObj1().getC1(), result.getObj1().getC1()); + assertEquals(container.getEnum1().name(), result.getEnum1().name()); + + + } } diff --git a/dozer-integrations/dozer-proto3/src/test/java/com/github/dozermapper/protobuf/vo/proto/TestContainerObject.java b/dozer-integrations/dozer-proto3/src/test/java/com/github/dozermapper/protobuf/vo/proto/TestContainerObject.java new file mode 100644 index 000000000..16993823c --- /dev/null +++ b/dozer-integrations/dozer-proto3/src/test/java/com/github/dozermapper/protobuf/vo/proto/TestContainerObject.java @@ -0,0 +1,60 @@ +/* + * Copyright 2005-2018 Dozer Project + * + * 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 + * + * http://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 com.github.dozermapper.protobuf.vo.proto; + +public class TestContainerObject { + public enum TestContainedEnum { + VALUE1, VALUE2; + } + + public static class TestContainedObject{ + private String c1; + + public TestContainedObject() { + + } + + public String getC1() { + return c1; + } + + public void setC1(String c1) { + this.c1 = c1; + } + } + + private TestContainedObject obj1; + private TestContainedEnum enum1; + + public TestContainerObject() { + } + + public TestContainedEnum getEnum1() { + return enum1; + } + + public TestContainedObject getObj1() { + return obj1; + } + + public void setEnum1(TestContainedEnum enum1) { + this.enum1 = enum1; + } + + public void setObj1(TestContainedObject obj1) { + this.obj1 = obj1; + } +} diff --git a/dozer-integrations/dozer-proto3/src/test/proto/ProtoTestObjectsMultipleFiles.proto b/dozer-integrations/dozer-proto3/src/test/proto/ProtoTestObjectsMultipleFiles.proto index 7dfa01eb8..9b3a8451b 100644 --- a/dozer-integrations/dozer-proto3/src/test/proto/ProtoTestObjectsMultipleFiles.proto +++ b/dozer-integrations/dozer-proto3/src/test/proto/ProtoTestObjectsMultipleFiles.proto @@ -25,3 +25,18 @@ message TestObject { message SimpleProtoTestObject { TestObject nested = 1; } + +message ContainerObject { + + enum ContainedEnum { + VALUE1 = 0; + VALUE2 = 1; + } + + message ContainedObject { + string c1 = 1; + } + + ContainedObject obj1 = 1; + ContainedEnum enum1 = 2; +} \ No newline at end of file diff --git a/dozer-integrations/dozer-proto3/src/test/resources/mappings/protoBeansMapping.xml b/dozer-integrations/dozer-proto3/src/test/resources/mappings/protoBeansMapping.xml index 829eb5eeb..ce314d196 100644 --- a/dozer-integrations/dozer-proto3/src/test/resources/mappings/protoBeansMapping.xml +++ b/dozer-integrations/dozer-proto3/src/test/resources/mappings/protoBeansMapping.xml @@ -87,4 +87,26 @@ + + com.github.dozermapper.protobuf.vo.proto.TestContainerObject.TestContainedObject + com.github.dozermapper.protobuf.vo.protomultiple.ContainerObject.ContainedObject + + c1 + c1 + + + + + com.github.dozermapper.protobuf.vo.proto.TestContainerObject + com.github.dozermapper.protobuf.vo.protomultiple.ContainerObject + + obj1 + obj1 + + + enum1 + enum1 + + +