1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 package com.helger.jcodemodel;
42
43 import java.io.File;
44 import java.io.IOException;
45 import java.io.PrintStream;
46 import java.nio.charset.Charset;
47 import java.util.ArrayList;
48 import java.util.Collections;
49 import java.util.HashMap;
50 import java.util.Iterator;
51 import java.util.List;
52 import java.util.Map;
53
54 import javax.annotation.Nonnegative;
55 import javax.annotation.Nonnull;
56 import javax.annotation.Nullable;
57 import javax.annotation.concurrent.NotThreadSafe;
58 import javax.lang.model.element.TypeElement;
59 import javax.lang.model.util.Elements;
60
61 import com.helger.jcodemodel.meta.CodeModelBuildingException;
62 import com.helger.jcodemodel.meta.ErrorTypeFound;
63 import com.helger.jcodemodel.meta.JCodeModelJavaxLangModelAdapter;
64 import com.helger.jcodemodel.util.JCSecureLoader;
65 import com.helger.jcodemodel.util.JCValueEnforcer;
66 import com.helger.jcodemodel.writer.FileCodeWriter;
67 import com.helger.jcodemodel.writer.ProgressCodeWriter;
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99 public final class JCodeModel
100 {
101
102
103
104
105
106 public static final Map <Class <?>, Class <?>> primitiveToBox;
107
108
109
110
111 public static final Map <Class <?>, Class <?>> boxToPrimitive;
112
113 static
114 {
115 final Map <Class <?>, Class <?>> m1 = new HashMap <Class <?>, Class <?>> ();
116 final Map <Class <?>, Class <?>> m2 = new HashMap <Class <?>, Class <?>> ();
117
118 m1.put (Boolean.class, Boolean.TYPE);
119 m1.put (Byte.class, Byte.TYPE);
120 m1.put (Character.class, Character.TYPE);
121 m1.put (Double.class, Double.TYPE);
122 m1.put (Float.class, Float.TYPE);
123 m1.put (Integer.class, Integer.TYPE);
124 m1.put (Long.class, Long.TYPE);
125 m1.put (Short.class, Short.TYPE);
126 m1.put (Void.class, Void.TYPE);
127
128
129 for (final Map.Entry <Class <?>, Class <?>> e : m1.entrySet ())
130 m2.put (e.getValue (), e.getKey ());
131
132 boxToPrimitive = Collections.unmodifiableMap (m1);
133 primitiveToBox = Collections.unmodifiableMap (m2);
134 }
135
136
137 private final Map <String, JPackage> m_aPackages = new HashMap <String, JPackage> ();
138
139
140 private final Map <Class <?>, JReferencedClass> m_aRefClasses = new HashMap <Class <?>, JReferencedClass> ();
141
142
143 public final JNullType NULL = new JNullType (this);
144
145 public final JPrimitiveType BOOLEAN = new JPrimitiveType (this, "boolean", Boolean.class, true);
146 public final JPrimitiveType BYTE = new JPrimitiveType (this, "byte", Byte.class, true);
147 public final JPrimitiveType CHAR = new JPrimitiveType (this, "char", Character.class, true);
148 public final JPrimitiveType DOUBLE = new JPrimitiveType (this, "double", Double.class, true);
149 public final JPrimitiveType FLOAT = new JPrimitiveType (this, "float", Float.class, true);
150 public final JPrimitiveType INT = new JPrimitiveType (this, "int", Integer.class, true);
151 public final JPrimitiveType LONG = new JPrimitiveType (this, "long", Long.class, true);
152 public final JPrimitiveType SHORT = new JPrimitiveType (this, "short", Short.class, true);
153 public final JPrimitiveType VOID = new JPrimitiveType (this, "void", Void.class, false);
154
155 protected static boolean getFileSystemCaseSensitivity ()
156 {
157 try
158 {
159
160
161 if (System.getProperty ("com.sun.codemodel.FileSystemCaseSensitive") != null)
162 return true;
163
164
165
166 if (System.getProperty ("com.helger.jcodemodel.FileSystemCaseSensitive") != null)
167 return true;
168 }
169 catch (final Exception e)
170 {
171
172 }
173
174
175 return File.separatorChar == '/';
176 }
177
178
179
180
181
182 protected final boolean isCaseSensitiveFileSystem = getFileSystemCaseSensitivity ();
183
184
185
186
187 private AbstractJClass m_aWildcard;
188
189
190 private Charset m_aBuildingCharset = null;
191
192
193 private String m_sBuildingNewLine = AbstractCodeWriter.getDefaultNewLine ();
194
195 public JCodeModel ()
196 {}
197
198
199
200
201
202
203
204
205 @Nonnull
206 public JPackage _package (@Nonnull final String name)
207 {
208 JPackage p = m_aPackages.get (name);
209 if (p == null)
210 {
211 p = new JPackage (name, this);
212 m_aPackages.put (name, p);
213 }
214 return p;
215 }
216
217 @Nonnull
218 public final JPackage rootPackage ()
219 {
220 return _package ("");
221 }
222
223
224
225
226 @Nonnull
227 public Iterator <JPackage> packages ()
228 {
229 return m_aPackages.values ().iterator ();
230 }
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245 @Nonnull
246 public JDefinedClass _class (final int nMods,
247 @Nonnull final String sFullyQualifiedClassName,
248 @Nonnull final EClassType eClassType) throws JClassAlreadyExistsException
249 {
250 final int nIdx = sFullyQualifiedClassName.lastIndexOf ('.');
251 if (nIdx < 0)
252 return rootPackage ()._class (nMods, sFullyQualifiedClassName, eClassType);
253 return _package (sFullyQualifiedClassName.substring (0, nIdx))._class (nMods,
254 sFullyQualifiedClassName.substring (nIdx +
255 1),
256 eClassType);
257 }
258
259
260
261
262
263
264
265
266
267
268 @Nonnull
269 public JDefinedClass _class (@Nonnull final String sFullyQualifiedClassName) throws JClassAlreadyExistsException
270 {
271 return _class (sFullyQualifiedClassName, EClassType.CLASS);
272 }
273
274
275
276
277
278
279
280
281
282
283
284
285 @Nonnull
286 public JDefinedClass _class (final int nMods,
287 @Nonnull final String sFullyQualifiedClassName) throws JClassAlreadyExistsException
288 {
289 return _class (nMods, sFullyQualifiedClassName, EClassType.CLASS);
290 }
291
292
293
294
295
296
297
298
299
300
301
302
303 @Nonnull
304 public JDefinedClass _class (@Nonnull final String sFullyQualifiedClassName,
305 @Nonnull final EClassType eClassType) throws JClassAlreadyExistsException
306 {
307 return _class (JMod.PUBLIC, sFullyQualifiedClassName, eClassType);
308 }
309
310
311
312
313
314
315
316
317
318
319
320
321
322 @Nonnull
323 public JDirectClass directClass (@Nonnull final String sName)
324 {
325 return directClass (EClassType.CLASS, sName);
326 }
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342 @Nonnull
343 public JDirectClass directClass (@Nonnull final EClassType eClassType, @Nonnull final String sName)
344 {
345 return new JDirectClass (this, null, eClassType, sName);
346 }
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375 @Nonnull
376 public JErrorClass errorClass (@Nonnull final String sMessage)
377 {
378 return errorClass (sMessage, null);
379 }
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410 @Nonnull
411 public JErrorClass errorClass (@Nonnull final String sMessage, @Nullable final String sName)
412 {
413 return new JErrorClass (this, sMessage, sName);
414 }
415
416
417
418
419
420
421
422 public boolean buildsErrorTypeRefs ()
423 {
424 final JPackage [] pkgs = m_aPackages.values ().toArray (new JPackage [m_aPackages.size ()]);
425
426 for (final JPackage pkg : pkgs)
427 {
428 if (pkg.buildsErrorTypeRefs ())
429 return true;
430 }
431 return false;
432 }
433
434
435
436
437
438
439
440
441
442 @Nullable
443 public JDefinedClass _getClass (@Nonnull final String sFullyQualifiedClassName)
444 {
445 final int nIndex = sFullyQualifiedClassName.lastIndexOf ('.');
446 if (nIndex < 0)
447 return rootPackage ()._getClass (sFullyQualifiedClassName);
448 return _package (sFullyQualifiedClassName.substring (0, nIndex))
449 ._getClass (sFullyQualifiedClassName.substring (nIndex +
450 1));
451 }
452
453
454
455
456
457
458
459
460 @Nonnull
461 public JAnonymousClass anonymousClass (@Nonnull final AbstractJClass aBaseClass)
462 {
463 return new JAnonymousClass (aBaseClass);
464 }
465
466
467
468
469
470
471
472
473 @Nonnull
474 public JAnonymousClass anonymousClass (@Nonnull final Class <?> aBaseClass)
475 {
476 return anonymousClass (ref (aBaseClass));
477 }
478
479
480
481
482
483 @Nullable
484 public Charset getBuildingCharset ()
485 {
486 return m_aBuildingCharset;
487 }
488
489
490
491
492
493
494
495
496
497 @Nonnull
498 public JCodeModel setBuildingCharset (@Nullable final Charset aCharset)
499 {
500 m_aBuildingCharset = aCharset;
501 return this;
502 }
503
504
505
506
507 public String getBuildingNewLine ()
508 {
509 return m_sBuildingNewLine;
510 }
511
512
513
514
515
516
517
518
519
520 @Nonnull
521 public JCodeModel setBuildingNewLine (@Nonnull final String sNewLine)
522 {
523 JCValueEnforcer.notEmpty (sNewLine, "NewLine");
524 m_sBuildingNewLine = sNewLine;
525 return this;
526 }
527
528
529
530
531
532
533
534
535
536
537
538
539 public void build (@Nonnull final File destDir, @Nullable final PrintStream status) throws IOException
540 {
541 build (destDir, destDir, status);
542 }
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558 public void build (@Nonnull final File srcDir,
559 @Nonnull final File resourceDir,
560 @Nullable final PrintStream status) throws IOException
561 {
562 AbstractCodeWriter res = new FileCodeWriter (resourceDir, m_aBuildingCharset, m_sBuildingNewLine);
563 AbstractCodeWriter src = new FileCodeWriter (srcDir, m_aBuildingCharset, m_sBuildingNewLine);
564 if (status != null)
565 {
566 src = new ProgressCodeWriter (src, status);
567 res = new ProgressCodeWriter (res, status);
568 }
569 build (src, res);
570 }
571
572
573
574
575
576
577
578
579
580 public void build (@Nonnull final File destDir) throws IOException
581 {
582 build (destDir, System.out);
583 }
584
585
586
587
588
589
590
591
592
593
594
595 public void build (@Nonnull final File srcDir, @Nonnull final File resourceDir) throws IOException
596 {
597 build (srcDir, resourceDir, System.out);
598 }
599
600
601
602
603
604
605
606
607
608 public void build (@Nonnull final AbstractCodeWriter out) throws IOException
609 {
610 build (out, out);
611 }
612
613
614
615
616
617
618
619
620
621
622
623 public void build (@Nonnull final AbstractCodeWriter source,
624 @Nonnull final AbstractCodeWriter resource) throws IOException
625 {
626 try
627 {
628 final JPackage [] pkgs = m_aPackages.values ().toArray (new JPackage [m_aPackages.size ()]);
629
630 for (final JPackage pkg : pkgs)
631 pkg.build (source, resource);
632 }
633 finally
634 {
635 source.close ();
636 resource.close ();
637 }
638 }
639
640
641
642
643
644 @Nonnegative
645 public int countArtifacts ()
646 {
647 int r = 0;
648 final JPackage [] pkgs = m_aPackages.values ().toArray (new JPackage [m_aPackages.size ()]);
649
650 for (final JPackage pkg : pkgs)
651 r += pkg.countArtifacts ();
652 return r;
653 }
654
655
656
657
658
659
660
661
662
663
664
665
666 @Nonnull
667 public AbstractJClass ref (@Nonnull final Class <?> clazz)
668 {
669 JReferencedClass aRefClass = m_aRefClasses.get (clazz);
670 if (aRefClass == null)
671 {
672 if (clazz.isPrimitive ())
673 {
674
675 throw new IllegalArgumentException (clazz + " is a primitive");
676 }
677
678 if (clazz.isArray ())
679 {
680 final Class <?> aComponentType = clazz.getComponentType ();
681
682 return new JArrayClass (this, _ref (aComponentType));
683 }
684
685 aRefClass = new JReferencedClass (this, clazz);
686 m_aRefClasses.put (clazz, aRefClass);
687 }
688 return aRefClass;
689 }
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720 @Nonnull
721 public JDefinedClass ref (@Nonnull final TypeElement element,
722 @Nonnull final Elements elementUtils) throws ErrorTypeFound, CodeModelBuildingException
723 {
724 final JCodeModelJavaxLangModelAdapter adapter = new JCodeModelJavaxLangModelAdapter (this, elementUtils);
725 return adapter.getClass (element);
726 }
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757 @Nonnull
758 public JDefinedClass refWithErrorTypes (@Nonnull final TypeElement element,
759 @Nonnull final Elements elementUtils) throws CodeModelBuildingException
760 {
761 final JCodeModelJavaxLangModelAdapter adapter = new JCodeModelJavaxLangModelAdapter (this, elementUtils);
762 return adapter.getClassWithErrorTypes (element);
763 }
764
765
766
767
768
769
770
771
772 @Nonnull
773 public AbstractJType _ref (@Nonnull final Class <?> c)
774 {
775 if (c.isPrimitive ())
776 return AbstractJType.parse (this, c.getName ());
777 return ref (c);
778 }
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793 @Nonnull
794 public AbstractJClass ref (@Nonnull final String sFullyQualifiedClassName)
795 {
796 try
797 {
798
799 return ref (JCSecureLoader.getContextClassLoader ().loadClass (sFullyQualifiedClassName));
800 }
801 catch (final ClassNotFoundException e)
802 {
803
804 }
805
806
807 try
808 {
809 return ref (Class.forName (sFullyQualifiedClassName));
810 }
811 catch (final ClassNotFoundException e)
812 {
813
814 }
815
816
817 return new JDirectClass (this, null, EClassType.CLASS, sFullyQualifiedClassName);
818 }
819
820
821
822
823
824 @Nonnull
825 public AbstractJClass wildcard ()
826 {
827 if (m_aWildcard == null)
828 m_aWildcard = ref (Object.class).wildcard ();
829 return m_aWildcard;
830 }
831
832
833
834
835
836
837
838
839
840
841
842
843 @Nonnull
844 public AbstractJType parseType (@Nonnull final String name)
845 {
846
847 if (name.endsWith ("[]"))
848 {
849
850 return parseType (name.substring (0, name.length () - 2)).array ();
851 }
852
853
854 try
855 {
856 return AbstractJType.parse (this, name);
857 }
858 catch (final IllegalArgumentException e)
859 {
860
861 }
862
863
864 return new TypeNameParser (name).parseTypeName ();
865 }
866
867 @NotThreadSafe
868 private final class TypeNameParser
869 {
870 private final String m_sTypeName;
871 private int m_nIdx;
872
873 public TypeNameParser (@Nonnull final String s)
874 {
875 m_sTypeName = s;
876 }
877
878
879
880
881
882
883
884 @Nonnull
885 AbstractJClass parseTypeName ()
886 {
887 final int nStart = m_nIdx;
888
889 if (m_sTypeName.charAt (m_nIdx) == '?')
890 {
891
892 m_nIdx++;
893 _skipWs ();
894
895 final String head = m_sTypeName.substring (m_nIdx);
896 if (head.startsWith ("extends"))
897 {
898
899 m_nIdx += 7;
900 _skipWs ();
901 return parseTypeName ().wildcard ();
902 }
903
904 if (head.startsWith ("super"))
905 {
906
907 m_nIdx += 5;
908 _skipWs ();
909 return parseTypeName ().wildcardSuper ();
910 }
911
912
913 throw new IllegalArgumentException ("only extends/super can follow ?, but found " +
914 m_sTypeName.substring (m_nIdx));
915 }
916
917 while (m_nIdx < m_sTypeName.length ())
918 {
919 final char ch = m_sTypeName.charAt (m_nIdx);
920 if (Character.isJavaIdentifierStart (ch) || Character.isJavaIdentifierPart (ch) || ch == '.')
921 m_nIdx++;
922 else
923 break;
924 }
925
926 final AbstractJClass clazz = ref (m_sTypeName.substring (nStart, m_nIdx));
927 return _parseSuffix (clazz);
928 }
929
930
931
932
933
934 @Nonnull
935 private AbstractJClass _parseSuffix (@Nonnull final AbstractJClass clazz)
936 {
937 if (m_nIdx == m_sTypeName.length ())
938 {
939
940 return clazz;
941 }
942
943 final char ch = m_sTypeName.charAt (m_nIdx);
944
945 if (ch == '<')
946 return _parseSuffix (_parseArguments (clazz));
947
948 if (ch == '[')
949 {
950 if (m_sTypeName.charAt (m_nIdx + 1) == ']')
951 {
952 m_nIdx += 2;
953 return _parseSuffix (clazz.array ());
954 }
955 throw new IllegalArgumentException ("Expected ']' but found " + m_sTypeName.substring (m_nIdx + 1));
956 }
957
958 return clazz;
959 }
960
961
962
963
964 private void _skipWs ()
965 {
966 while (Character.isWhitespace (m_sTypeName.charAt (m_nIdx)) && m_nIdx < m_sTypeName.length ())
967 m_nIdx++;
968 }
969
970
971
972
973
974
975 @Nonnull
976 private AbstractJClass _parseArguments (@Nonnull final AbstractJClass rawType)
977 {
978 if (m_sTypeName.charAt (m_nIdx) != '<')
979 throw new IllegalArgumentException ();
980 m_nIdx++;
981
982 final List <AbstractJClass> args = new ArrayList <AbstractJClass> ();
983
984 while (true)
985 {
986 args.add (parseTypeName ());
987 if (m_nIdx == m_sTypeName.length ())
988 throw new IllegalArgumentException ("Missing '>' in " + m_sTypeName);
989 final char ch = m_sTypeName.charAt (m_nIdx);
990 if (ch == '>')
991 return rawType.narrow (args);
992
993 if (ch != ',')
994 throw new IllegalArgumentException (m_sTypeName);
995 m_nIdx++;
996 }
997 }
998 }
999 }