001package ball.game.scrabble; 002/*- 003 * ########################################################################## 004 * Game Applications and Utilities 005 * $Id: PremiumProcessor.html 5431 2020-02-12 19:03:17Z ball $ 006 * $HeadURL: svn+ssh://svn.hcf.dev/var/spool/scm/repository.svn/hcf-dev/blog/2019-07-08-fivethirtyeight-best-scrabble-string/src/main/resources/javadoc/src-html/ball/game/scrabble/PremiumProcessor.html $ 007 * %% 008 * Copyright (C) 2010 - 2020 Allen D. Ball 009 * %% 010 * Licensed under the Apache License, Version 2.0 (the "License"); 011 * you may not use this file except in compliance with the License. 012 * You may obtain a copy of the License at 013 * 014 * http://www.apache.org/licenses/LICENSE-2.0 015 * 016 * Unless required by applicable law or agreed to in writing, software 017 * distributed under the License is distributed on an "AS IS" BASIS, 018 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 019 * See the License for the specific language governing permissions and 020 * limitations under the License. 021 * ########################################################################## 022 */ 023import ball.annotation.ServiceProviderFor; 024import ball.annotation.processing.AbstractAnnotationProcessor; 025import ball.annotation.processing.For; 026import java.lang.annotation.Annotation; 027import java.util.HashSet; 028import java.util.List; 029import javax.annotation.processing.ProcessingEnvironment; 030import javax.annotation.processing.Processor; 031import javax.annotation.processing.RoundEnvironment; 032import javax.lang.model.element.Element; 033import javax.lang.model.element.TypeElement; 034import lombok.NoArgsConstructor; 035import lombok.ToString; 036 037import static javax.lang.model.element.Modifier.ABSTRACT; 038import static javax.lang.model.element.Modifier.PUBLIC; 039import static javax.tools.Diagnostic.Kind.ERROR; 040 041/** 042 * {@link Processor} implementation to check {@link Class}es annotated with 043 * {@link LetterPremium} or {@link WordPremium}: 044 * <ol> 045 * <li value="1">Are an instance of {@link SQ},</li> 046 * <li value="2">Concrete, and</li> 047 * <li value="3"> 048 * Are annotated with only one of {@link LetterPremium} or 049 * {@link WordPremium} 050 * </li> 051 * </ol> 052 * 053 * @author {@link.uri mailto:ball@hcf.dev Allen D. Ball} 054 * @version $Revision: 5431 $ 055 */ 056@ServiceProviderFor({ Processor.class }) 057@For({ LetterPremium.class, WordPremium.class }) 058@NoArgsConstructor @ToString 059public class PremiumProcessor extends AbstractAnnotationProcessor { 060 private TypeElement supertype = null; 061 062 @Override 063 public void init(ProcessingEnvironment processingEnv) { 064 super.init(processingEnv); 065 066 try { 067 supertype = getTypeElementFor(SQ.class); 068 } catch (Exception exception) { 069 print(ERROR, null, exception); 070 } 071 } 072 073 @Override 074 public void process(RoundEnvironment roundEnv, 075 TypeElement annotation, 076 Element element) throws Exception { 077 switch (element.getKind()) { 078 case CLASS: 079 if (isAssignable(element.asType(), supertype.asType())) { 080 if (! element.getModifiers().contains(ABSTRACT)) { 081 if (hasPublicNoArgumentConstructor(element)) { 082 HashSet<TypeElement> set = new HashSet<>(); 083 084 for (Class<? extends Annotation> type : 085 getSupportedAnnotationTypeList()) { 086 if (element.getAnnotation(type) != null) { 087 set.add(getTypeElementFor(type)); 088 } 089 } 090 091 set.remove(annotation); 092 093 if (! set.isEmpty()) { 094 print(ERROR, 095 element, 096 element.getKind() + " annotated with " 097 + AT + annotation.getSimpleName() 098 + " but is also annotated with " 099 + AT + set.iterator().next().getSimpleName()); 100 } 101 } else { 102 print(ERROR, 103 element, 104 element.getKind() + " annotated with " 105 + AT + annotation.getSimpleName() 106 + " but does not have a " + PUBLIC 107 + " no-argument constructor"); 108 } 109 } else { 110 print(ERROR, 111 element, 112 element.getKind() + " annotated with " 113 + AT + annotation.getSimpleName() 114 + " but is " + ABSTRACT); 115 } 116 } else { 117 print(ERROR, 118 element, 119 element.getKind() + " annotated with " 120 + AT + annotation.getSimpleName() 121 + " but is not a subclass of " 122 + supertype.getQualifiedName()); 123 } 124 break; 125 126 default: 127 break; 128 } 129 } 130}