1+ /*
2+ * Licensed to the Apache Software Foundation (ASF) under one or more
3+ * contributor license agreements. See the NOTICE file distributed with
4+ * this work for additional information regarding copyright ownership.
5+ * The ASF licenses this file to You under the Apache License, Version 2.0
6+ * (the "License"); you may not use this file except in compliance with
7+ * the License. You may obtain a copy of the License at
8+ *
9+ * http://www.apache.org/licenses/LICENSE-2.0
10+ *
11+ * Unless required by applicable law or agreed to in writing, software
12+ * distributed under the License is distributed on an "AS IS" BASIS,
13+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+ * See the License for the specific language governing permissions and
15+ * limitations under the License.
16+ */
17+
18+ package io .microsphere .annotation .processor ;
19+
20+ import io .microsphere .annotation .ConfigurationProperty ;
21+ import io .microsphere .annotation .processor .model .util .ConfigurationPropertyJSONElementVisitor ;
22+ import io .microsphere .json .JSONArray ;
23+
24+ import javax .annotation .processing .AbstractProcessor ;
25+ import javax .annotation .processing .Messager ;
26+ import javax .annotation .processing .ProcessingEnvironment ;
27+ import javax .annotation .processing .Processor ;
28+ import javax .annotation .processing .RoundEnvironment ;
29+ import javax .annotation .processing .SupportedAnnotationTypes ;
30+ import javax .lang .model .SourceVersion ;
31+ import javax .lang .model .element .Element ;
32+ import javax .lang .model .element .TypeElement ;
33+ import java .util .Iterator ;
34+ import java .util .Set ;
35+
36+ import static io .microsphere .annotation .processor .ConfigurationPropertyAnnotationProcessor .CONFIGURATION_PROPERTY_ANNOTATION_CLASS_NAME ;
37+ import static io .microsphere .annotation .processor .util .MessagerUtils .printNote ;
38+ import static io .microsphere .constants .SymbolConstants .COMMA_CHAR ;
39+ import static io .microsphere .constants .SymbolConstants .LEFT_SQUARE_BRACKET_CHAR ;
40+ import static io .microsphere .constants .SymbolConstants .RIGHT_SQUARE_BRACKET_CHAR ;
41+ import static javax .lang .model .SourceVersion .latestSupported ;
42+ import static javax .tools .StandardLocation .CLASS_OUTPUT ;
43+
44+ /**
45+ * The {@link Processor} for the {@link ConfigurationProperty} annotation
46+ *
47+ * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
48+ * @see ConfigurationProperty
49+ * @since 1.0.0
50+ */
51+ @ SupportedAnnotationTypes (value = CONFIGURATION_PROPERTY_ANNOTATION_CLASS_NAME )
52+ public class ConfigurationPropertyAnnotationProcessor extends AbstractProcessor {
53+
54+ /**
55+ * The {@link Class class} name of {@link ConfigurationProperty}
56+ */
57+ public static final String CONFIGURATION_PROPERTY_ANNOTATION_CLASS_NAME = "io.microsphere.annotation.ConfigurationProperty" ;
58+
59+ /**
60+ * The resource name of {@link ConfigurationProperty} metadata
61+ */
62+ public static final String CONFIGURATION_PROPERTY_METADATA_RESOURCE_NAME = "META-INF/microsphere/configuration-properties.json" ;
63+
64+ private Messager messager ;
65+
66+ private StringBuilder jsonBuilder ;
67+
68+ private ResourceProcessor classPathResourceProcessor ;
69+
70+ @ Override
71+ public synchronized void init (ProcessingEnvironment processingEnv ) {
72+ super .init (processingEnv );
73+ this .messager = processingEnv .getMessager ();
74+ this .jsonBuilder = new StringBuilder ();
75+ this .classPathResourceProcessor = new ResourceProcessor (processingEnv , CLASS_OUTPUT );
76+ }
77+
78+ @ Override
79+ public boolean process (Set <? extends TypeElement > annotations , RoundEnvironment roundEnv ) {
80+ if (roundEnv .processingOver ()) {
81+ writeMetadata ();
82+ } else {
83+ resolveMetadata (roundEnv );
84+ }
85+ return false ;
86+ }
87+
88+ private void resolveMetadata (RoundEnvironment roundEnv ) {
89+ Set <? extends Element > elements = roundEnv .getRootElements ();
90+ if (!elements .isEmpty ()) {
91+ ConfigurationPropertyJSONElementVisitor visitor = new ConfigurationPropertyJSONElementVisitor (processingEnv );
92+
93+ Iterator <? extends Element > iterator = elements .iterator ();
94+ jsonBuilder .append (LEFT_SQUARE_BRACKET_CHAR );
95+ while (iterator .hasNext ()) {
96+ Element element = iterator .next ();
97+ element .accept (visitor , jsonBuilder );
98+ }
99+
100+ int lastIndex = jsonBuilder .length () - 1 ;
101+ if (COMMA_CHAR == jsonBuilder .charAt (lastIndex )) {
102+ jsonBuilder .setCharAt (lastIndex , RIGHT_SQUARE_BRACKET_CHAR );
103+ } else {
104+ jsonBuilder .append (RIGHT_SQUARE_BRACKET_CHAR );
105+ }
106+ }
107+ }
108+
109+ private void writeMetadata () {
110+ classPathResourceProcessor .processInResourceWriter (CONFIGURATION_PROPERTY_METADATA_RESOURCE_NAME , writer -> {
111+ JSONArray jsonArray = new JSONArray (jsonBuilder .toString ());
112+ String formatedJSON = jsonArray .toString (2 );
113+ writer .write (formatedJSON );
114+ printNote (this .messager , "The generated metadata JSON of @{} : \n {}" , CONFIGURATION_PROPERTY_ANNOTATION_CLASS_NAME , formatedJSON );
115+ });
116+ }
117+
118+ @ Override
119+ public SourceVersion getSupportedSourceVersion () {
120+ return latestSupported ();
121+ }
122+ }
123+
0 commit comments