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 Java array -> proto List #300

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,7 @@
import java.util.Map;
import java.util.Set;

import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.*;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;

Expand All @@ -41,6 +38,8 @@
import org.mapstruct.ap.spi.MapStructProcessingEnvironment;
import org.mapstruct.ap.spi.util.IntrospectorUtils;

import static javax.lang.model.type.TypeKind.ARRAY;

/**
* @author Arne Seime
*/
Expand All @@ -61,17 +60,21 @@ public class ProtobufAccessorNamingStrategy extends DefaultAccessorNamingStrateg

protected static final List<String> INTERNAL_SPECIAL_METHOD_BEGINNINGS = Arrays.asList("remove", "clear", "mutable", "merge", "putAll");

protected TypeMirror protobufMesageOrBuilderType;
protected TypeMirror protobufMesageOrBuilderType;
protected TypeMirror iterable;

@Override
public void init(MapStructProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);

TypeElement typeElement = elementUtils.getTypeElement(PROTOBUF_MESSAGE_OR_BUILDER);
if (typeElement != null) {
protobufMesageOrBuilderType = typeElement.asType();
}
}
TypeElement typeElement = elementUtils.getTypeElement(PROTOBUF_MESSAGE_OR_BUILDER);
if (typeElement != null) {
protobufMesageOrBuilderType = typeElement.asType();
}

iterable = typeUtils.erasure(typeUtils.getDeclaredType(elementUtils.getTypeElement(Iterable.class.getName())));
}


private boolean isSpecialMethod(ExecutableElement method) {
if (!isMethodFromProtobufGeneratedClass(method)) {
Expand Down Expand Up @@ -113,25 +116,26 @@ private boolean isSpecialMethod(ExecutableElement method) {
return false;
}

@Override
public boolean isGetterMethod(ExecutableElement method) {
String methodName = method.getSimpleName().toString();
@Override
public boolean isGetterMethod(ExecutableElement method) {
String methodName = method.getSimpleName().toString();
if (isMethodFromProtobufGeneratedClass(method)) {
if (methodName.endsWith("Builder")) {
return false;
}

// if (methodName.endsWith("Builder")) {
// return false;
// }

if (methodName.endsWith("OrBuilder")) {
return false;
}
if (methodName.endsWith("OrBuilder")) {
return false;
}

if (methodName.endsWith("OrBuilderList")) {
return false;
}
if (methodName.endsWith("OrBuilderList")) {
return false;
}

if (methodName.endsWith(BUILDER_LIST_SUFFIX)) {
return false;
}
if (methodName.endsWith(BUILDER_LIST_SUFFIX)) {
return false;
}
}

if (INTERNAL_METHODS.contains(methodName)) {
return false;
Expand All @@ -158,19 +162,28 @@ private boolean isOneOfCaseSelector(ExecutableElement method) {
return false;
}

@Override
public boolean isSetterMethod(ExecutableElement method) {
String methodName = method.getSimpleName().toString();
// Iterable TypeMirror check

@Override
public boolean isSetterMethod(ExecutableElement method) {
String methodName = method.getSimpleName().toString();

if (INTERNAL_METHODS.contains(methodName)) {
return false;
} else {
if (isSpecialMethod(method)) {
return false;
}
List<? extends VariableElement> parameters = method.getParameters();
if (methodName.startsWith("addAll") && parameters.size() > 0) {
VariableElement variableElement = parameters.get(0);
if (isIterable(variableElement))
return true; // return if method name is addAllXxx and first parameter is Iterable
}
}
return super.isSetterMethod(method);
}

if (INTERNAL_METHODS.contains(methodName)) {
return false;
} else {
if (isSpecialMethod(method)) {
return false;
}
return super.isSetterMethod(method);
}
}

@Override
protected boolean isFluentSetter(ExecutableElement method) {
Expand Down Expand Up @@ -232,33 +245,48 @@ public String getElementName(ExecutableElement adderMethod) {
return methodName;
}

@Override
public String getPropertyName(ExecutableElement getterOrSetterMethod) {
String methodName = getterOrSetterMethod.getSimpleName().toString();

boolean isGetMutableMap = isGetMutableMap(getterOrSetterMethod);
boolean isGetUnmodifiableMap = isGetUnmodifiableMap(getterOrSetterMethod);

if (isGetList(getterOrSetterMethod) || isSetList(getterOrSetterMethod) || isGetMutableMap) {
Element receiver = getterOrSetterMethod.getEnclosingElement();
if (receiver != null && (receiver.getKind() == ElementKind.CLASS || receiver.getKind() == ElementKind.INTERFACE)) {
TypeElement type = (TypeElement) receiver;
if (isProtobufGeneratedMessage(type)) {
if (isGetMutableMap) {
// 'getMutable...'
return IntrospectorUtils.decapitalize(methodName.substring(10));
} else if (isGetUnmodifiableMap) {
// 'get...'
return IntrospectorUtils.decapitalize(methodName.substring(3));
} else {
// 'get...List'
return IntrospectorUtils.decapitalize(methodName.substring(3, methodName.length() - 4));
}
}
}
}
return super.getPropertyName(getterOrSetterMethod);
}
@Override
public String getPropertyName(ExecutableElement getterOrSetterMethod) {
String methodName = getterOrSetterMethod.getSimpleName().toString();

boolean isGetMutableMap = isGetMutableMap(getterOrSetterMethod);
boolean isGetUnmodifiableMap = isGetUnmodifiableMap(getterOrSetterMethod);
Element receiver = getterOrSetterMethod.getEnclosingElement();
if (receiver != null && (receiver.getKind() == ElementKind.CLASS || receiver.getKind() == ElementKind.INTERFACE)) {
TypeElement type = (TypeElement) receiver;
if (isProtobufGeneratedMessage(type)) {
if (isGetList(getterOrSetterMethod) || isSetList(getterOrSetterMethod) || isGetMutableMap) {
if (isGetMutableMap) {
// 'getMutable...'
return IntrospectorUtils.decapitalize(methodName.substring(10));
} else if (isGetUnmodifiableMap) {
// 'get...'
return IntrospectorUtils.decapitalize(methodName.substring(3));
} else if (methodName.startsWith("addAll")) {
// 'addAllXxx' -> 'xxx'
return IntrospectorUtils.decapitalize(methodName.substring(6));
} else {
// 'get...List'
return IntrospectorUtils.decapitalize(methodName.substring(3, methodName.length() - 4));
}
} else {
if (typeUtils.isAssignable(getterOrSetterMethod.getReturnType(), protobufMesageOrBuilderType)) {
// addXxxBuilder
if ((methodName.startsWith("add") || methodName.startsWith("get"))) {
if (methodName.endsWith("Builder")) {
return IntrospectorUtils.decapitalize(methodName.substring(3, methodName.length() - 7));
} else {
return IntrospectorUtils.decapitalize(methodName.substring(3));
}

}

}
}
}
}
return super.getPropertyName(getterOrSetterMethod);
}

private boolean isGetList(ExecutableElement element) {
return element.getSimpleName().toString().startsWith("get") && isListType(element.getReturnType());
Expand All @@ -274,17 +302,29 @@ private boolean isGetMutableMap(ExecutableElement element) {
return element.getSimpleName().toString().startsWith("getMutable") && isMapType(element.getReturnType());
}

private boolean isSetList(ExecutableElement element) {
if (element.getSimpleName().toString().startsWith("set") && element.getParameters().size() == 1) {
TypeMirror param = element.getParameters().get(0).asType();
return isListType(param);
}
return false;
}

private boolean isListType(TypeMirror t) {
return t.toString().startsWith(List.class.getCanonicalName()) || t.toString().startsWith(PROTOBUF_STRING_LIST_TYPE);
}
private boolean isSetList(ExecutableElement element) {
if (element.getSimpleName().toString().startsWith("addAll") && element.getParameters().size() == 1) {
List<? extends VariableElement> parameters = element.getParameters();
if (parameters.size() > 0) {
VariableElement variableElement = parameters.get(0);
if (isIterable(variableElement)) {
return true;
}
}
}
if (element.getSimpleName().toString().startsWith("set") && element.getParameters().size() == 1) {
TypeMirror param = element.getParameters().get(0).asType();
return isListType(param);
}
return false;
}

private boolean isListType(TypeMirror t) {
if (t.getKind() == ARRAY) {
return true;
}
return t.toString().startsWith(List.class.getCanonicalName()) || t.toString().startsWith(PROTOBUF_STRING_LIST_TYPE);
}

private boolean isMapType(TypeMirror t) {
return t.toString().startsWith(Map.class.getCanonicalName());
Expand Down Expand Up @@ -325,4 +365,12 @@ private boolean isMethodFromProtobufBuilder(ExecutableElement method) {
TypeElement cls = (TypeElement) method.getEnclosingElement();
return cls.getSuperclass().toString().startsWith(PROTOBUF_BUILDER);
}

private boolean isIterable(VariableElement variableElement) {
TypeMirror typeMirror = variableElement.asType();
if (typeUtils.isAssignable(typeMirror, iterable)) {
return true;
}
return false;
}
}
9 changes: 9 additions & 0 deletions usage/src/main/java/no/entur/mapstruct/spi/protobuf/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ public class User {
List<String> rv14;
List<ByteString> rv15;
List<Status> rv16;
Status[] rv17;
MultiNumber multiNumber;
List<MultiNumber> repMultiNumbers;
private String id;
Expand Down Expand Up @@ -444,4 +445,12 @@ public List<User> getUsers() {
public void setUsers(List<User> users) {
this.users = users;
}

public Status[] getRv17() {
return rv17;
}

public void setRv17(Status[] rv17) {
this.rv17 = rv17;
}
}
1 change: 1 addition & 0 deletions usage/src/main/proto/User.proto
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ message UserDTO {
repeated bytes rv15 = 114;

repeated EnumStatus rv16 = 115;
repeated EnumStatus rv17 = 116;
// repeated google.protobuf.Any rv17 = 116;

repeated MultiNumberDTO rep_multi_numbers = 120;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ private User generateUser() {
user.setRv14(Arrays.asList("some string"));
user.setRv15(Arrays.asList(ByteString.copyFromUtf8("some byte string")));
user.setRv16(Arrays.asList(Status.STARTED));
user.setRv17(new Status[]{Status.STARTED, Status.STOPPED});

MultiNumber mm = new MultiNumber();
mm.setNumber(1);
Expand Down Expand Up @@ -242,6 +243,10 @@ private void assertUser(User orig, User back) {
assertEquals(orig.getRv16().size(), back.getRv16().size());
assertEquals(orig.getRv16().get(0), back.getRv16().get(0));

assertEquals(orig.getRv17().length, back.getRv17().length);
assertEquals(orig.getRv17()[0], back.getRv17()[0]);
assertEquals(orig.getRv17()[1], back.getRv17()[1]);

assertNotNull(back.getPoliceDepartment());
assertEquals(back.getPoliceDepartment().getName(), "POLICE");
// WILL FAIL: Mapstruct cannot handle presence checker on oneOfs : assertNull(back.getFireDepartment());
Expand Down