001package ball.annotation.processing; 002/*- 003 * ########################################################################## 004 * Utilities 005 * %% 006 * Copyright (C) 2008 - 2022 Allen D. Ball 007 * %% 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 * ########################################################################## 020 */ 021import ball.annotation.ServiceProviderFor; 022import java.beans.ConstructorProperties; 023import java.util.List; 024import java.util.Objects; 025import java.util.Set; 026import java.util.stream.Stream; 027import javax.annotation.processing.Processor; 028import javax.annotation.processing.RoundEnvironment; 029import javax.lang.model.element.AnnotationMirror; 030import javax.lang.model.element.AnnotationValue; 031import javax.lang.model.element.Element; 032import javax.lang.model.element.ExecutableElement; 033import javax.lang.model.element.TypeElement; 034import javax.lang.model.element.VariableElement; 035import lombok.NoArgsConstructor; 036import lombok.ToString; 037import org.apache.commons.lang3.StringUtils; 038 039import static java.util.stream.Collectors.toList; 040import static javax.tools.Diagnostic.Kind.ERROR; 041import static javax.tools.Diagnostic.Kind.WARNING; 042 043/** 044 * {@link Processor} implementation to verify {@link ConstructorProperties} 045 * annotation are actual bean properties of the 046 * {@link java.lang.reflect.Constructor}'s {@link Class}. 047 * 048 * @author {@link.uri mailto:ball@hcf.dev Allen D. Ball} 049 */ 050@ServiceProviderFor({ Processor.class }) 051@For({ ConstructorProperties.class }) 052@NoArgsConstructor @ToString 053public class ConstructorPropertiesProcessor extends AnnotatedProcessor { 054 @Override 055 public void process(RoundEnvironment roundEnv, TypeElement annotation, Element element) { 056 super.process(roundEnv, annotation, element); 057 058 AnnotationMirror mirror = getAnnotationMirror(element, annotation); 059 AnnotationValue value = getAnnotationValue(mirror, "value"); 060 List<String> names = 061 Stream.of(value) 062 .filter(Objects::nonNull) 063 .map(t -> (List<?>) t.getValue()) 064 .flatMap(List::stream) 065 .map(t -> (AnnotationValue) t) 066 .map(t -> (String) t.getValue()) 067 .collect(toList()); 068 List<? extends VariableElement> parameters = ((ExecutableElement) element).getParameters(); 069 070 if (names.size() != parameters.size()) { 071 print(WARNING, element, mirror, value, "value() does not match %s parameters", element.getKind()); 072 } 073 074 TypeElement type = (TypeElement) element.getEnclosingElement(); 075 Set<String> properties = getPropertyNames(type); 076 077 names.stream() 078 .filter(StringUtils::isNotEmpty) 079 .filter(t -> (! properties.contains(t))) 080 .forEach(t -> print(WARNING, element, mirror, "bean property '%s' not defined", t)); 081 } 082}