22
33import java .io .BufferedWriter ;
44import java .io .IOException ;
5- import java .util .ArrayList ;
6- import java .util .List ;
7- import java .util .Map ;
8- import java .util .Set ;
5+ import java .util .*;
96
107import javax .annotation .processing .AbstractProcessor ;
118import javax .annotation .processing .RoundEnvironment ;
129import javax .annotation .processing .SupportedAnnotationTypes ;
1310import javax .annotation .processing .SupportedSourceVersion ;
1411import javax .lang .model .SourceVersion ;
15- import javax .lang .model .element .Element ;
16- import javax .lang .model .element .ElementKind ;
17- import javax .lang .model .element .ExecutableElement ;
18- import javax .lang .model .element .Modifier ;
19- import javax .lang .model .element .TypeElement ;
20- import javax .lang .model .element .VariableElement ;
12+ import javax .lang .model .element .*;
2113import javax .lang .model .type .ArrayType ;
2214import javax .lang .model .type .DeclaredType ;
2315import javax .lang .model .type .TypeKind ;
2416import javax .lang .model .type .TypeMirror ;
2517import javax .tools .Diagnostic .Kind ;
2618
19+ import io .github .danthe1st .json_compile .impl .data .*;
2720import org .json .JSONArray ;
2821import org .json .JSONObject ;
2922
3023import javax .tools .JavaFileObject ;
3124
3225import io .github .danthe1st .json_compile .api .GenerateJSON ;
33- import io .github .danthe1st .json_compile .impl .data .JSONOperation ;
34- import io .github .danthe1st .json_compile .impl .data .JSONOperation .OperationType ;
35- import io .github .danthe1st .json_compile .impl .data .VariableDefinition ;
3626
3727@ SupportedAnnotationTypes ("io.github.danthe1st.json_compile.api.GenerateJSON" )
3828@ SupportedSourceVersion (SourceVersion .RELEASE_11 )
3929public class JSONCreator extends AbstractProcessor {
4030
4131 private static final String JSONOBJECT_PARAM_NAME = "data" ;
4232
43- private static final Map <String , String > simpleAssignments = Map .of ("java.lang.String" , "String" , "int" , "Int" , "long" , "Long" );
33+ private static final Map <String , String > simpleAssignments = Map .of ("java.lang.String" , "String" ,
34+ "int" , "Int" ,"java.lang.Integer" ,"Int" ,
35+ "long" , "Long" ,"java.lang.Long" ,"Long" );
4436
4537 @ Override
4638 public boolean process (Set <? extends TypeElement > annotations , RoundEnvironment roundEnv ) {
@@ -92,8 +84,7 @@ private void generateJSON(Element element, String fullyQualidiedClassName, Class
9284 break ;
9385 case FIELD :
9486
95- operations .add (new JSONOperation (((VariableElement ) innerElement ).getSimpleName ().toString (),
96- OperationType .FIELD , innerElement .asType ()));
87+ operations .add (new FieldOperation (((VariableElement ) innerElement ).getSimpleName ().toString (), innerElement .asType ()));
9788 break ;
9889 case METHOD :
9990 JSONOperation op = loadMethodInfo (innerElement );
@@ -148,6 +139,8 @@ private void generateJSON(Element element, String fullyQualidiedClassName, Class
148139 writer .endClass ();
149140 }
150141
142+
143+
151144 //TODO arrays/collections, more primitives
152145 private void addPropertyFromJSON (ClassWriter writer , JSONOperation jsonOperation ,String jsonObjectName ) throws IOException {
153146 TypeMirror type = jsonOperation .getType ();
@@ -157,9 +150,7 @@ private void addPropertyFromJSON(ClassWriter writer, JSONOperation jsonOperation
157150 //TODO test, add in addPropertyToJSON
158151 ArrayType arrayType = (ArrayType ) type ;
159152
160- String jsonArrayName =jsonObjectName +capitalizeFirst (jsonOperation .getAttributeName ()).replaceAll ("\\ [.*]" ,"" )+"JsonArray" ;
161- String optArgument =getJSONAccessName (jsonOperation );
162- writer .addAssignment (JSONArray .class .getCanonicalName () +" " +jsonArrayName ,jsonObjectName +".optJSONArray(" +optArgument +")" );
153+ String jsonArrayName =addCreateJSONArrayCode (writer ,jsonOperation ,jsonObjectName );
163154
164155 String actualArrayName =jsonOperation .getAttributeName ().replaceAll ("\\ [.*]" ,"" )+"DataArray" ;
165156 writer .addAssignment (arrayType .getComponentType ().toString ()+"[] " +actualArrayName ,"null" );
@@ -180,65 +171,94 @@ private void addPropertyFromJSON(ClassWriter writer, JSONOperation jsonOperation
180171 String counterVar =jsonArrayName +"Counter" ;
181172 writer .beginSimpleFor ("int " +counterVar +"=0" ,counterVar +"<" +jsonArrayName +".length()" ,counterVar +"++" );
182173
183- addPropertyFromJSON (writer ,new JSONOperation (actualArrayName +"[" +counterVar +"]" , OperationType . ARRAY_ELEMENT ,arrayType .getComponentType ()),jsonArrayName );
174+ addPropertyFromJSON (writer ,new ArrayElementOperation (actualArrayName +"[" +counterVar +"]" ,arrayType .getComponentType ()),jsonArrayName );
184175
185176 writer .endFor ();
186177 val =actualArrayName ;
187178 writer .endIf ();
179+ }else if (isCollection (type )){
180+ TypeMirror collectionType =getCollectionType (type );
181+ if (collectionType ==null ){
182+ processingEnv .getMessager ().printMessage (Kind .ERROR ,"Cannot infer type" ,type instanceof DeclaredType ? ((DeclaredType ) type ).asElement () : null );
183+ return ;
184+ }
185+ String jsonArrayName =addCreateJSONArrayCode (writer ,jsonOperation ,jsonObjectName );
186+ String counterVar =jsonArrayName +"Counter" ;
187+
188+ String dataName =jsonArrayName +"Data" ;
189+ writer .addAssignment (typeName +" " +dataName ,jsonOperation .getAccessor ("ret" ));//TODO check if ret is the correct object
190+ writer .beginIf (jsonArrayName +"!=null" );
191+ writer .beginSimpleFor ("int " +counterVar +"=0" ,counterVar +"<" +jsonArrayName +".length()" ,counterVar +"++" );
192+
193+
194+ addPropertyFromJSON (writer ,new CollectionElementOperation (dataName ,counterVar /*TODO what to do with collections of collections? How to create those?*/ ,collectionType ),jsonArrayName );
195+
196+ val =dataName ;
197+
198+ writer .endIf ();
199+ writer .endFor ();
188200 } else if (simpleAssignments .containsKey (typeName )) {
189- String name =getJSONAccessName (jsonOperation );
201+ String name =jsonOperation . getJSONAccessName ();
190202 val = jsonObjectName + ".opt" + simpleAssignments .get (typeName ) + "(" + name + ")" ;
191203 } else {
192204 TypeElement referencedElement = processingEnv .getElementUtils ().getTypeElement (typeName );
193205 if (referencedElement != null && referencedElement .getAnnotation (GenerateJSON .class ) != null ) {
194- val = referencedElement .toString () + "JSONLoader.fromJSON(" + jsonObjectName + ".optJSONObject(\" " + jsonOperation .getAttributeName () + " \ " ))" ;
206+ val = referencedElement .toString () + "JSONLoader.fromJSON(" + jsonObjectName + ".optJSONObject(" + jsonOperation .getJSONAccessName () + "))" ;
195207 }
196208 }
197209 if (val == null ) {
198210 processingEnv .getMessager ().printMessage (Kind .ERROR , "type " + typeName + " is not supported" );
199211 } else {
200- switch (jsonOperation .getOpType ()) {
201- case FIELD :
202- writer .addAssignment ("ret." + jsonOperation .getAttributeName (), val );
203- break ;
204- case PROPERTY :
205- writer .addMethodCall ("ret" , "set" + capitalizeFirst (jsonOperation .getAttributeName ()), val );
206- break ;
207- case ARRAY_ELEMENT :
208- writer .addAssignment (jsonOperation .getAttributeName (),val );
209- break ;
210- }
212+ writer .addStatement (jsonOperation .getMutator ("ret" ,val ));
211213 }
212214 }
213215
214- private String getJSONAccessName (JSONOperation jsonOperation ){
215- String name =jsonOperation .getAttributeName ();
216- if (jsonOperation .getOpType ()==OperationType .ARRAY_ELEMENT ){
217- name =name .substring (name .indexOf ('[' )+1 ,name .indexOf (']' ));
218- }else {
219- name ='"' +name +'"' ;
216+ private String addCreateJSONArrayCode (ClassWriter writer , JSONOperation jsonOperation , String jsonObjectName ) throws IOException {
217+ String jsonArrayName =jsonObjectName +capitalizeFirst (jsonOperation .getAttributeName ()).replaceAll ("\\ [.*]" ,"" )+"JsonArray" ;
218+ String optArgument =jsonOperation .getJSONAccessName ();
219+ writer .addAssignment (JSONArray .class .getCanonicalName () +" " +jsonArrayName ,jsonObjectName +".optJSONArray(" +optArgument +")" );
220+ return jsonArrayName ;
221+ }
222+
223+ private boolean isCollection (TypeMirror type ) {
224+ return getCollectionType (type )!=null ;//TODO this may return false with generics
225+ //return processingEnv.getTypeUtils().isSubtype(type,processingEnv.getElementUtils().getTypeElement(Collection.class.getSimpleName()).asType());
226+ }
227+
228+ private TypeMirror getCollectionType (TypeMirror type ){
229+ if (!(type instanceof DeclaredType )) {
230+ return null ;
231+ }
232+ TypeElement elem = (TypeElement ) ((DeclaredType ) type ).asElement ();
233+ for (TypeMirror iFace : elem .getInterfaces ()) {
234+ if (Collection .class .getCanonicalName ().equals (((DeclaredType )iFace ).asElement ().toString ())){
235+
236+ List <? extends TypeMirror > typeArgs = ((DeclaredType ) iFace ).getTypeArguments ();
237+ if (typeArgs .size ()==1 ){
238+ TypeMirror genericArg = typeArgs .get (0 );
239+ if (genericArg .getKind ()==TypeKind .TYPEVAR ){
240+ for (int i = 0 ; i < elem .getTypeParameters ().size (); i ++) {
241+ if (elem .getTypeParameters ().get (i ).getSimpleName ().toString ().equals (genericArg .toString ())){
242+ return ((DeclaredType ) type ).getTypeArguments ().get (i );//TODO test this
243+ }
244+ }
245+ }
246+ return genericArg ;
247+ }
248+ return null ;
249+ }
220250 }
221- return name ;
251+ return null ;
222252 }
223253
224254 private void addPropertyToJSON (ClassWriter writer , JSONOperation jsonOperation ,String jsonObjectName ) throws IOException {
225255 TypeMirror type = jsonOperation .getType ();
226256 String typeName = type .toString ();
227- String val = null ;
228- switch (jsonOperation .getOpType ()) {
229- case FIELD :
230- val = "obj." + jsonOperation .getAttributeName ();
231- break ;
232- case PROPERTY :
233- val = "obj.get" + capitalizeFirst (jsonOperation .getAttributeName ()) + "()" ;
234- break ;
235- case ARRAY_ELEMENT :
236- val =jsonOperation .getAttributeName ();
237- }
257+ String val = jsonOperation .getAccessor ("obj" );//TODO check if obj is correct here
258+
238259 if (val == null ) {
239260 processingEnv .getMessager ().printMessage (Kind .ERROR , "type " + typeName + " is currenly not supported" );
240261 }else if (type .getKind ()==TypeKind .ARRAY ){
241- //TODO
242262 ArrayType arrayType = (ArrayType ) type ;
243263
244264 String jsonArrayName =jsonObjectName +jsonOperation .getAttributeName ().replaceAll ("\\ [.*]" ,"" );
@@ -250,20 +270,62 @@ private void addPropertyToJSON(ClassWriter writer, JSONOperation jsonOperation,S
250270 String counterVar =jsonArrayName +"Counter" ;
251271 writer .beginSimpleFor ("int " +counterVar +"=0" ,counterVar +"<" +arrayName +".length" ,counterVar +"++" );
252272
253- writer . addMethodCall ( jsonArrayName , "put" , arrayName +"[" +counterVar +"]" ); //TODO recursion?
273+ addPropertyToJSON ( writer , new ArrayElementOperation ( arrayName +"[" +counterVar +"]" , arrayType . getComponentType ()), jsonArrayName );
254274
255275 writer .endFor ();
256- writer .addMethodCall (jsonObjectName ,"put" ,"\" " +jsonOperation .getAttributeName ()+"\" " ,jsonArrayName );
276+ if (jsonOperation .isChildType ()){
277+ writer .addMethodCall (jsonObjectName ,"put" ,jsonArrayName );
278+ }else {
279+ writer .addMethodCall (jsonObjectName ,"put" ,"\" " +jsonOperation .getAttributeName ()+"\" " ,jsonArrayName );
280+ }
257281 writer .endIf ();
282+ }else if (isCollection (type )){
283+ if (jsonOperation .isChildType ()){
284+ processingEnv .getMessager ().printMessage (Kind .ERROR ,"Collections of collections are not supported" ,type instanceof DeclaredType ? ((DeclaredType ) type ).asElement () : null );
285+ return ;
286+ }
287+ TypeMirror collectionType = getCollectionType (type );
288+ if (collectionType ==null ){
289+ processingEnv .getMessager ().printMessage (Kind .ERROR ,"Cannot infer type" ,type instanceof DeclaredType ? ((DeclaredType ) type ).asElement () : null );
290+ return ;
291+ }
292+
293+ String dataName =jsonObjectName +capitalizeFirst (jsonOperation .getAttributeName ()).replaceAll ("\\ [.*]" ,"" );
294+ String collectionName =dataName +"Collection" ;
295+ String jsonArrayName =dataName +"JSONArray" ;//TODO null safe
296+
297+ writer .addAssignment (JSONArray .class .getCanonicalName ()+" " +jsonArrayName ,"new " +JSONArray .class .getCanonicalName ()+"()" );
298+ writer .addAssignment (type .toString ()+" " +collectionName ,val );
299+ writer .beginIf (collectionName +"!=null" );
300+ writer .beginForEach (collectionType .toString (),dataName ,collectionName );
301+
302+ addPropertyToJSON (writer ,new CollectionElementOperation (collectionName ,dataName ,collectionType ),jsonArrayName );
303+
304+ writer .endFor ();
305+ writer .endIf ();
306+
307+ if (jsonOperation .isChildType ()){
308+ writer .addMethodCall (jsonObjectName ,"put" ,jsonArrayName );
309+ }else {
310+ writer .addMethodCall (jsonObjectName ,"put" ,"\" " +jsonOperation .getAttributeName ()+"\" " ,jsonArrayName );
311+ }
312+
258313 } else if (simpleAssignments .containsKey (typeName )) {
259- writer .addMethodCall (jsonObjectName , "put" , "\" " + jsonOperation .getAttributeName () + "\" " , val );
314+ if (jsonOperation .isChildType ()){
315+ writer .addMethodCall (jsonObjectName , "put" , val );
316+ }else {
317+ writer .addMethodCall (jsonObjectName , "put" , "\" " + jsonOperation .getAttributeName () + "\" " , val );
318+ }
260319 } else {
261320 TypeElement referencedElement = processingEnv .getElementUtils ().getTypeElement (typeName );
262321 if (referencedElement != null && referencedElement .getAnnotation (GenerateJSON .class ) != null ) {
263- writer .addMethodCall (jsonObjectName , "put" , "\" " + jsonOperation .getAttributeName () + "\" " , referencedElement .toString () + "JSONLoader.toJSONObject(" + val + ")" );
322+ if (jsonOperation .isChildType ()){
323+ writer .addMethodCall (jsonObjectName , "put" , referencedElement .toString () + "JSONLoader.toJSONObject(" + val + ")" );
324+ }else {
325+ writer .addMethodCall (jsonObjectName , "put" , "\" " + jsonOperation .getAttributeName () + "\" " , referencedElement .toString () + "JSONLoader.toJSONObject(" + val + ")" );
326+ }
264327 }
265328 }
266-
267329 }
268330
269331 private void addReturnIfNull (ClassWriter writer , String paramName ) throws IOException {
@@ -286,15 +348,15 @@ private JSONOperation loadMethodInfo(Element element) {
286348 for (Element sibling : element .getEnclosingElement ().getEnclosedElements ()) {
287349 if (sibling .getKind () == ElementKind .METHOD
288350 && ("set" + name .substring (3 )).equals (sibling .getSimpleName ().toString ())) {
289- return new JSONOperation (propName , OperationType . PROPERTY ,
351+ return new PropertyOperation (propName ,
290352 ((ExecutableElement ) element ).getReturnType ());
291353 }
292354 }
293355 }
294356 return null ;
295357 }
296358
297- private String capitalizeFirst (String toCapitalize ){
359+ public static String capitalizeFirst (String toCapitalize ){
298360 return Character .toUpperCase (toCapitalize .charAt (0 )) + (toCapitalize .length () > 1 ? toCapitalize .substring (1 ):"" );
299361 }
300362}
0 commit comments