From c484281576d9c996b9d87d8a9865fba6051237f0 Mon Sep 17 00:00:00 2001 From: Grig Alex Date: Sun, 5 Sep 2021 17:07:58 +0300 Subject: [PATCH] Add support of package/protected access --- .../dev/alexengrig/metter/FieldChecker.java | 23 +++++++++ .../element/descriptor/MethodDescriptor.java | 10 +++- .../element/descriptor/TypeDescriptor.java | 2 +- .../BaseMethodSupplierProcessor.java | 51 ++++++++++++------- .../GetterSupplierFactoryProcessor.java | 51 +++++++++++++------ .../processor/GetterSupplierProcessor.java | 11 ++-- .../SetterSupplierFactoryProcessor.java | 51 +++++++++++++------ .../processor/SetterSupplierProcessor.java | 11 ++-- 8 files changed, 154 insertions(+), 56 deletions(-) create mode 100644 src/main/java/dev/alexengrig/metter/FieldChecker.java diff --git a/src/main/java/dev/alexengrig/metter/FieldChecker.java b/src/main/java/dev/alexengrig/metter/FieldChecker.java new file mode 100644 index 0000000..18ae20a --- /dev/null +++ b/src/main/java/dev/alexengrig/metter/FieldChecker.java @@ -0,0 +1,23 @@ +/* + * Copyright 2020-2021 Alexengrig Dev. + * + * 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 dev.alexengrig.metter; + +import dev.alexengrig.metter.element.descriptor.FieldDescriptor; + +public interface FieldChecker { + boolean isTarget(FieldDescriptor fieldDescriptor); +} diff --git a/src/main/java/dev/alexengrig/metter/element/descriptor/MethodDescriptor.java b/src/main/java/dev/alexengrig/metter/element/descriptor/MethodDescriptor.java index 2bfc493..8d8fde4 100644 --- a/src/main/java/dev/alexengrig/metter/element/descriptor/MethodDescriptor.java +++ b/src/main/java/dev/alexengrig/metter/element/descriptor/MethodDescriptor.java @@ -46,6 +46,7 @@ public class MethodDescriptor extends ElementDescriptor { * @since 0.1.1 */ protected transient Boolean isNotPrivate; + protected transient Boolean isPublic; /** * Constructs with an executable element. @@ -103,11 +104,18 @@ public TypeDescriptor getParent() { */ public boolean isNotPrivate() { if (isNotPrivate == null) { - isNotPrivate = element.getModifiers().stream().noneMatch(Modifier.PRIVATE::equals); + isNotPrivate = !element.getModifiers().contains(Modifier.PRIVATE); } return isNotPrivate; } + public boolean isPublic() { + if (isPublic == null) { + isPublic = element.getModifiers().contains(Modifier.PUBLIC); + } + return isPublic; + } + /** * Checks if method has no parameters. * diff --git a/src/main/java/dev/alexengrig/metter/element/descriptor/TypeDescriptor.java b/src/main/java/dev/alexengrig/metter/element/descriptor/TypeDescriptor.java index fda69a3..5b7a283 100644 --- a/src/main/java/dev/alexengrig/metter/element/descriptor/TypeDescriptor.java +++ b/src/main/java/dev/alexengrig/metter/element/descriptor/TypeDescriptor.java @@ -90,7 +90,7 @@ public String getPackage() { if (lastIndexOfDot > 0) { return qualifiedName.substring(0, lastIndexOfDot); } - throw new IllegalStateException("No package"); + return ""; } /** diff --git a/src/main/java/dev/alexengrig/metter/processor/BaseMethodSupplierProcessor.java b/src/main/java/dev/alexengrig/metter/processor/BaseMethodSupplierProcessor.java index 6a2c134..5713754 100644 --- a/src/main/java/dev/alexengrig/metter/processor/BaseMethodSupplierProcessor.java +++ b/src/main/java/dev/alexengrig/metter/processor/BaseMethodSupplierProcessor.java @@ -16,6 +16,7 @@ package dev.alexengrig.metter.processor; +import dev.alexengrig.metter.FieldChecker; import dev.alexengrig.metter.element.descriptor.ElementDescriptor; import dev.alexengrig.metter.element.descriptor.FieldDescriptor; import dev.alexengrig.metter.element.descriptor.MethodDescriptor; @@ -32,6 +33,7 @@ import java.lang.annotation.Annotation; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import java.util.Set; /** @@ -167,8 +169,9 @@ protected JavaFileObject createSourceFile(String qualifiedClassName) { protected Map createField2MethodMap(D descriptor) { Map field2Method = new HashMap<>(); Set fields = getFields(descriptor); + FieldChecker fieldChecker = getFieldChecker(descriptor); for (FieldDescriptor field : fields) { - if (isTargetField(field)) { + if (fieldChecker.isTarget(field)) { field2Method.put(field.getName(), getMethod(field)); } } @@ -202,14 +205,7 @@ protected Map createField2MethodMap(D descriptor) { */ protected abstract Set getExcludedFields(D descriptor); - /** - * Checks if a field descriptor is target field. - * - * @param field descriptor - * @return {@code field} is target field. - * @since 0.1.0 - */ - protected abstract boolean isTargetField(FieldDescriptor field); + protected abstract FieldChecker getFieldChecker(D descriptor); /** * Returns a method for a field descriptor. @@ -228,14 +224,20 @@ protected Map createField2MethodMap(D descriptor) { * @since 0.1.1 */ protected boolean hasGetterMethod(FieldDescriptor field) { - String getter = getGetterMethod(field); + return getGetter(field).isPresent(); + } + + protected Optional getGetter(FieldDescriptor field) { + String getter = getGetterMethodName(field); TypeDescriptor type = field.getParent(); - if (type.hasMethod(getter)) { - Set methods = type.getMethods(getter); - return methods.stream().anyMatch(method -> method.isNotPrivate() && method.hasNoParameters() - && field.getTypeName().equals(method.getTypeName())); + if (!type.hasMethod(getter)) { + return Optional.empty(); } - return false; + Set methods = type.getMethods(getter); + return methods.stream() + .filter(method -> method.isNotPrivate() && method.hasNoParameters() + && field.getTypeName().equals(method.getTypeName())) + .findFirst(); } /** @@ -245,7 +247,7 @@ protected boolean hasGetterMethod(FieldDescriptor field) { * @return getter-method for {@code field} * @since 0.1.1 */ - protected String getGetterMethod(FieldDescriptor field) { + protected String getGetterMethodName(FieldDescriptor field) { String methodNamePrefix = "boolean".equals(field.getTypeName()) ? "is" : "get"; String name = field.getName(); return methodNamePrefix + Strings.capitalize(name); @@ -260,7 +262,7 @@ protected String getGetterMethod(FieldDescriptor field) { * @since 0.1.1 */ protected boolean hasSetterMethod(FieldDescriptor field) { - String methodName = getSetterMethod(field); + String methodName = getSetterMethodName(field); TypeDescriptor type = field.getParent(); if (type.hasMethod(methodName)) { Set methods = type.getMethods(methodName); @@ -270,6 +272,19 @@ protected boolean hasSetterMethod(FieldDescriptor field) { return false; } + protected Optional getSetter(FieldDescriptor field) { + String methodName = getSetterMethodName(field); + TypeDescriptor type = field.getParent(); + if (!type.hasMethod(methodName)) { + return Optional.empty(); + } + Set methods = type.getMethods(methodName); + return methods.stream() + .filter(method -> method.isNotPrivate() && "void".equals(method.getTypeName()) + && method.hasOnlyOneParameter(field.getTypeName())) + .findFirst(); + } + /** * Returns a setter-method for a field descriptor. * @@ -277,7 +292,7 @@ protected boolean hasSetterMethod(FieldDescriptor field) { * @return setter-method for {@code field} * @since 0.1.1 */ - protected String getSetterMethod(FieldDescriptor field) { + protected String getSetterMethodName(FieldDescriptor field) { String name = field.getName(); return "set" + Strings.capitalize(name); } diff --git a/src/main/java/dev/alexengrig/metter/processor/GetterSupplierFactoryProcessor.java b/src/main/java/dev/alexengrig/metter/processor/GetterSupplierFactoryProcessor.java index 59a4f7f..5b25b61 100644 --- a/src/main/java/dev/alexengrig/metter/processor/GetterSupplierFactoryProcessor.java +++ b/src/main/java/dev/alexengrig/metter/processor/GetterSupplierFactoryProcessor.java @@ -17,6 +17,7 @@ package dev.alexengrig.metter.processor; import com.google.auto.service.AutoService; +import dev.alexengrig.metter.FieldChecker; import dev.alexengrig.metter.annotation.GetterSupplier; import dev.alexengrig.metter.annotation.GetterSupplierFactory; import dev.alexengrig.metter.element.descriptor.FieldDescriptor; @@ -32,6 +33,7 @@ import javax.annotation.processing.Processor; import java.util.Arrays; import java.util.HashSet; +import java.util.Optional; import java.util.Set; @AutoService(Processor.class) @@ -74,25 +76,44 @@ protected Set getExcludedFields(MethodDescriptor descriptor) { } @Override - protected boolean isTargetField(FieldDescriptor field) { - if (field.hasAnnotation(Getter.class)) { - return !field.getAnnotation(Getter.class) - .map(Getter::value) - .filter(AccessLevel.PRIVATE::equals) - .isPresent(); + protected FieldChecker getFieldChecker(MethodDescriptor descriptor) { + String methodPackage; + if (descriptor.getParent().hasPackage()) { + methodPackage = descriptor.getParent().getPackage(); + } else { + methodPackage = ""; } - TypeDescriptor type = field.getParent(); - if (type.hasAnnotation(Getter.class)) { - return !type.getAnnotation(Getter.class) - .map(Getter::value) - .filter(AccessLevel.PRIVATE::equals) - .isPresent(); - } - return type.hasAnnotation(Data.class) || hasGetterMethod(field); + return field -> { + if (field.hasAnnotation(Getter.class)) { + return !field.getAnnotation(Getter.class) + .map(Getter::value) + .filter(AccessLevel.PRIVATE::equals) + .isPresent(); + } + TypeDescriptor type = field.getParent(); + if (type.hasAnnotation(Getter.class)) { + return !type.getAnnotation(Getter.class) + .map(Getter::value) + .filter(AccessLevel.PRIVATE::equals) + .isPresent(); + } + if (type.hasAnnotation(Data.class)) { + return true; + } + Optional getterOptional = getGetter(field); + if (!getterOptional.isPresent()) { + return false; + } + MethodDescriptor method = getterOptional.get(); + if (method.isPublic()) { + return true; + } + return methodPackage.equals(field.getParent().getPackage()); + }; } @Override protected String getMethod(FieldDescriptor field) { - return field.getParent().getQualifiedName() + "::" + getGetterMethod(field); + return field.getParent().getQualifiedName() + "::" + getGetterMethodName(field); } } diff --git a/src/main/java/dev/alexengrig/metter/processor/GetterSupplierProcessor.java b/src/main/java/dev/alexengrig/metter/processor/GetterSupplierProcessor.java index f7bfbc2..d773875 100644 --- a/src/main/java/dev/alexengrig/metter/processor/GetterSupplierProcessor.java +++ b/src/main/java/dev/alexengrig/metter/processor/GetterSupplierProcessor.java @@ -17,6 +17,7 @@ package dev.alexengrig.metter.processor; import com.google.auto.service.AutoService; +import dev.alexengrig.metter.FieldChecker; import dev.alexengrig.metter.annotation.GetterSupplier; import dev.alexengrig.metter.element.descriptor.FieldDescriptor; import dev.alexengrig.metter.element.descriptor.TypeDescriptor; @@ -107,6 +108,11 @@ protected Set getExcludedFields(TypeDescriptor descriptor) { .orElseThrow(() -> new MetterException("Type " + descriptor + " has no annotation: " + annotationClass)); } + @Override + protected FieldChecker getFieldChecker(TypeDescriptor descriptor) { + return this::isTargetField; + } + /** * Checks if a field descriptor has {@link lombok.Getter} (not private) annotation * or a type descriptor of field descriptor has {@link lombok.Getter} (not private) annotation @@ -120,8 +126,7 @@ protected Set getExcludedFields(TypeDescriptor descriptor) { * or type descriptor of {@code descriptor} has a getter method * @since 0.1.1 */ - @Override - protected boolean isTargetField(FieldDescriptor field) { + private boolean isTargetField(FieldDescriptor field) { if (field.hasAnnotation(Getter.class)) { return !field.getAnnotation(Getter.class) .map(Getter::value) @@ -147,6 +152,6 @@ protected boolean isTargetField(FieldDescriptor field) { */ @Override protected String getMethod(FieldDescriptor field) { - return field.getParent().getQualifiedName() + "::" + getGetterMethod(field); + return field.getParent().getQualifiedName() + "::" + getGetterMethodName(field); } } diff --git a/src/main/java/dev/alexengrig/metter/processor/SetterSupplierFactoryProcessor.java b/src/main/java/dev/alexengrig/metter/processor/SetterSupplierFactoryProcessor.java index 5d08b39..c5f6c05 100644 --- a/src/main/java/dev/alexengrig/metter/processor/SetterSupplierFactoryProcessor.java +++ b/src/main/java/dev/alexengrig/metter/processor/SetterSupplierFactoryProcessor.java @@ -17,6 +17,7 @@ package dev.alexengrig.metter.processor; import com.google.auto.service.AutoService; +import dev.alexengrig.metter.FieldChecker; import dev.alexengrig.metter.annotation.SetterSupplier; import dev.alexengrig.metter.annotation.SetterSupplierFactory; import dev.alexengrig.metter.element.descriptor.FieldDescriptor; @@ -32,6 +33,7 @@ import javax.annotation.processing.Processor; import java.util.Arrays; import java.util.HashSet; +import java.util.Optional; import java.util.Set; @AutoService(Processor.class) @@ -74,25 +76,44 @@ protected Set getExcludedFields(MethodDescriptor descriptor) { } @Override - protected boolean isTargetField(FieldDescriptor field) { - if (field.hasAnnotation(Setter.class)) { - return !field.getAnnotation(Setter.class) - .map(Setter::value) - .filter(AccessLevel.PRIVATE::equals) - .isPresent(); + protected FieldChecker getFieldChecker(MethodDescriptor descriptor) { + String methodPackage; + if (descriptor.getParent().hasPackage()) { + methodPackage = descriptor.getParent().getPackage(); + } else { + methodPackage = ""; } - TypeDescriptor type = field.getParent(); - if (type.hasAnnotation(Setter.class)) { - return !type.getAnnotation(Setter.class) - .map(Setter::value) - .filter(AccessLevel.PRIVATE::equals) - .isPresent(); - } - return type.hasAnnotation(Data.class) || hasSetterMethod(field); + return field -> { + if (field.hasAnnotation(Setter.class)) { + return !field.getAnnotation(Setter.class) + .map(Setter::value) + .filter(AccessLevel.PRIVATE::equals) + .isPresent(); + } + TypeDescriptor type = field.getParent(); + if (type.hasAnnotation(Setter.class)) { + return !type.getAnnotation(Setter.class) + .map(Setter::value) + .filter(AccessLevel.PRIVATE::equals) + .isPresent(); + } + if (type.hasAnnotation(Data.class)) { + return true; + } + Optional setterOptional = getSetter(field); + if (!setterOptional.isPresent()) { + return false; + } + MethodDescriptor method = setterOptional.get(); + if (method.isPublic()) { + return true; + } + return methodPackage.equals(field.getParent().getPackage()); + }; } @Override protected String getMethod(FieldDescriptor field) { - return "(instance, value) -> instance." + getSetterMethod(field) + "((" + field.getTypeName() + ") value)"; + return "(instance, value) -> instance." + getSetterMethodName(field) + "((" + field.getTypeName() + ") value)"; } } diff --git a/src/main/java/dev/alexengrig/metter/processor/SetterSupplierProcessor.java b/src/main/java/dev/alexengrig/metter/processor/SetterSupplierProcessor.java index aa9e11d..8f224f1 100644 --- a/src/main/java/dev/alexengrig/metter/processor/SetterSupplierProcessor.java +++ b/src/main/java/dev/alexengrig/metter/processor/SetterSupplierProcessor.java @@ -17,6 +17,7 @@ package dev.alexengrig.metter.processor; import com.google.auto.service.AutoService; +import dev.alexengrig.metter.FieldChecker; import dev.alexengrig.metter.annotation.SetterSupplier; import dev.alexengrig.metter.element.descriptor.FieldDescriptor; import dev.alexengrig.metter.element.descriptor.TypeDescriptor; @@ -107,6 +108,11 @@ protected Set getExcludedFields(TypeDescriptor descriptor) { .orElseThrow(() -> new MetterException("Type " + descriptor + " has no annotation: " + annotationClass)); } + @Override + protected FieldChecker getFieldChecker(TypeDescriptor descriptor) { + return this::isTargetField; + } + /** * Checks if a field descriptor has {@link lombok.Setter} annotation (not private) * or a type descriptor of field descriptor has {@link lombok.Setter} annotation (not private) @@ -120,8 +126,7 @@ protected Set getExcludedFields(TypeDescriptor descriptor) { * or type descriptor of {@code descriptor} has a setter method * @since 0.1.0 */ - @Override - protected boolean isTargetField(FieldDescriptor field) { + private boolean isTargetField(FieldDescriptor field) { if (field.hasAnnotation(Setter.class)) { return !field.getAnnotation(Setter.class) .map(Setter::value) @@ -147,6 +152,6 @@ protected boolean isTargetField(FieldDescriptor field) { */ @Override protected String getMethod(FieldDescriptor field) { - return "(instance, value) -> instance." + getSetterMethod(field) + "((" + field.getTypeName() + ") value)"; + return "(instance, value) -> instance." + getSetterMethodName(field) + "((" + field.getTypeName() + ") value)"; } }