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.BufferedOutputStream;
44 import java.io.BufferedWriter;
45 import java.io.File;
46 import java.io.IOException;
47 import java.io.OutputStream;
48 import java.io.PrintWriter;
49 import java.io.Writer;
50 import java.lang.annotation.Annotation;
51 import java.util.ArrayList;
52 import java.util.Collection;
53 import java.util.Collections;
54 import java.util.HashMap;
55 import java.util.HashSet;
56 import java.util.Iterator;
57 import java.util.List;
58 import java.util.Map;
59 import java.util.Set;
60 import java.util.TreeMap;
61
62 import javax.annotation.Nonnull;
63 import javax.annotation.Nullable;
64
65 import com.helger.jcodemodel.util.JCValueEnforcer;
66
67
68
69
70 public class JPackage implements IJDeclaration, IJGenerable, IJClassContainer <JDefinedClass>, IJAnnotatable, Comparable <JPackage>, IJDocCommentable
71 {
72
73
74
75 private final String m_sName;
76
77 private final JCodeModel m_aOwner;
78
79
80
81
82 private final Map <String, JDefinedClass> m_aClasses = new TreeMap <String, JDefinedClass> ();
83
84
85
86
87 private final Set <AbstractJResourceFile> m_aResources = new HashSet <AbstractJResourceFile> ();
88
89
90
91
92
93
94 private final Map <String, JDefinedClass> m_aUpperCaseClassMap;
95
96
97
98
99 private List <JAnnotationUse> m_aAnnotations;
100
101
102
103
104 private JDocComment m_aJavaDoc;
105
106
107
108
109
110
111
112
113
114
115
116 protected JPackage (@Nonnull final String sName, @Nonnull final JCodeModel aOwner)
117 {
118 JCValueEnforcer.notNull (sName, "Name");
119 if (sName.equals ("."))
120 throw new IllegalArgumentException ("Package name . is not allowed");
121 JCValueEnforcer.notNull (aOwner, "CodeModel");
122
123 m_aOwner = aOwner;
124 m_sName = sName;
125 if (m_aOwner.isCaseSensitiveFileSystem)
126 m_aUpperCaseClassMap = null;
127 else
128 m_aUpperCaseClassMap = new HashMap <String, JDefinedClass> ();
129 }
130
131 @Nullable
132 public IJClassContainer <?> parentContainer ()
133 {
134 return parent ();
135 }
136
137
138
139
140
141 @Nullable
142 public JPackage parent ()
143 {
144 if (isUnnamed ())
145 return null;
146
147 final int idx = m_sName.lastIndexOf ('.');
148 if (idx < 0)
149 return null;
150 return m_aOwner._package (m_sName.substring (0, idx));
151 }
152
153 public boolean isClass ()
154 {
155 return false;
156 }
157
158 public boolean isPackage ()
159 {
160 return true;
161 }
162
163 @Nonnull
164 public JPackage getPackage ()
165 {
166 return this;
167 }
168
169
170
171
172
173
174
175
176
177
178
179
180 @Nonnull
181 public JDefinedClass _class (final int nMods, @Nonnull final String sName) throws JClassAlreadyExistsException
182 {
183 return _class (nMods, sName, EClassType.CLASS);
184 }
185
186 @Nonnull
187 public JDefinedClass _class (final int nMods,
188 @Nonnull final String sName,
189 @Nonnull final EClassType eClassType) throws JClassAlreadyExistsException
190 {
191 if (m_aClasses.containsKey (sName))
192 throw new JClassAlreadyExistsException (m_aClasses.get (sName));
193
194
195 final JDefinedClass c = new JDefinedClass (this, nMods, sName, eClassType);
196
197 if (m_aUpperCaseClassMap != null)
198 {
199 final String sUpperName = sName.toUpperCase ();
200 final JDefinedClass dc = m_aUpperCaseClassMap.get (sUpperName);
201 if (dc != null)
202 throw new JClassAlreadyExistsException (dc);
203 m_aUpperCaseClassMap.put (sUpperName, c);
204 }
205 m_aClasses.put (sName, c);
206 return c;
207 }
208
209
210
211
212 @Nonnull
213 public JDefinedClass _class (@Nonnull final String sName) throws JClassAlreadyExistsException
214 {
215 return _class (JMod.PUBLIC, sName);
216 }
217
218
219
220
221
222
223
224
225 @Nullable
226 public JDefinedClass _getClass (@Nullable final String sName)
227 {
228 return m_aClasses.get (sName);
229 }
230
231
232
233
234
235
236
237 public int compareTo (@Nonnull final JPackage aOther)
238 {
239 return m_sName.compareTo (aOther.m_sName);
240 }
241
242
243
244
245
246
247
248
249
250
251 @Nonnull
252 public JDefinedClass _interface (final int nMods, @Nonnull final String sName) throws JClassAlreadyExistsException
253 {
254 return _class (nMods, sName, EClassType.INTERFACE);
255 }
256
257
258
259
260 @Nonnull
261 public JDefinedClass _interface (@Nonnull final String sName) throws JClassAlreadyExistsException
262 {
263 return _interface (JMod.PUBLIC, sName);
264 }
265
266
267
268
269
270
271
272
273
274
275
276
277 @Nonnull
278 public JDefinedClass _annotationTypeDeclaration (final int mods,
279 @Nonnull final String name) throws JClassAlreadyExistsException
280 {
281 return _class (mods, name, EClassType.ANNOTATION_TYPE_DECL);
282 }
283
284
285
286
287
288
289
290
291
292
293 @Nonnull
294 public JDefinedClass _annotationTypeDeclaration (@Nonnull final String name) throws JClassAlreadyExistsException
295 {
296 return _annotationTypeDeclaration (JMod.PUBLIC, name);
297 }
298
299
300
301
302
303
304
305
306
307
308
309
310 @Nonnull
311 public JDefinedClass _enum (final int mods, @Nonnull final String name) throws JClassAlreadyExistsException
312 {
313 return _class (mods, name, EClassType.ENUM);
314 }
315
316
317
318
319
320
321
322
323
324
325 @Nonnull
326 public JDefinedClass _enum (@Nonnull final String name) throws JClassAlreadyExistsException
327 {
328 return _enum (JMod.PUBLIC, name);
329 }
330
331
332
333
334
335
336
337
338 @Nonnull
339 public AbstractJResourceFile addResourceFile (@Nonnull final AbstractJResourceFile rsrc)
340 {
341 JCValueEnforcer.notNull (rsrc, "ResourceFile");
342 m_aResources.add (rsrc);
343 return rsrc;
344 }
345
346
347
348
349
350
351
352
353 public boolean hasResourceFile (@Nullable final String name)
354 {
355 for (final AbstractJResourceFile r : m_aResources)
356 if (r.name ().equals (name))
357 return true;
358 return false;
359 }
360
361
362
363
364
365
366 @Nonnull
367 public Iterator <AbstractJResourceFile> propertyFiles ()
368 {
369 return m_aResources.iterator ();
370 }
371
372
373
374
375
376
377
378 @Nonnull
379 public JDocComment javadoc ()
380 {
381 if (m_aJavaDoc == null)
382 m_aJavaDoc = new JDocComment (owner ());
383 return m_aJavaDoc;
384 }
385
386
387
388
389
390
391
392 public void remove (@Nonnull final AbstractJClass c)
393 {
394 if (c._package () != this)
395 throw new IllegalArgumentException ("the specified class is not a member of this package," +
396 " or it is a referenced class");
397
398
399
400 m_aClasses.remove (c.name ());
401 if (m_aUpperCaseClassMap != null)
402 m_aUpperCaseClassMap.remove (c.name ().toUpperCase ());
403 }
404
405
406
407
408
409
410
411
412
413
414 @Nonnull
415 public AbstractJClass ref (@Nonnull final String sClassLocalName) throws ClassNotFoundException
416 {
417 if (sClassLocalName.indexOf ('.') >= 0)
418 throw new IllegalArgumentException ("JClass name contains '.': " + sClassLocalName);
419
420 String sFQCN;
421 if (isUnnamed ())
422 sFQCN = "";
423 else
424 sFQCN = m_sName + '.';
425 sFQCN += sClassLocalName;
426
427 return m_aOwner.ref (Class.forName (sFQCN));
428 }
429
430
431
432
433
434
435
436
437 @Nonnull
438 public JPackage subPackage (@Nonnull final String sSubPackageName)
439 {
440 if (isUnnamed ())
441 return owner ()._package (sSubPackageName);
442 return owner ()._package (m_sName + '.' + sSubPackageName);
443 }
444
445
446
447
448 @Nonnull
449 public Collection <JDefinedClass> classes ()
450 {
451 return m_aClasses.values ();
452 }
453
454
455
456
457
458
459
460
461 public boolean isDefined (@Nullable final String classLocalName)
462 {
463 for (final JDefinedClass clazz : m_aClasses.values ())
464 if (clazz.name ().equals (classLocalName))
465 return true;
466 return false;
467 }
468
469
470
471
472
473
474 public final boolean isUnnamed ()
475 {
476 return m_sName.length () == 0;
477 }
478
479
480
481
482
483
484
485
486 @Nonnull
487 public String name ()
488 {
489 return m_sName;
490 }
491
492
493
494
495 @Nonnull
496 public final JCodeModel owner ()
497 {
498 return m_aOwner;
499 }
500
501 @Nonnull
502 public JAnnotationUse annotate (@Nonnull final AbstractJClass clazz)
503 {
504 if (isUnnamed ())
505 throw new IllegalArgumentException ("the root package cannot be annotated");
506
507 if (m_aAnnotations == null)
508 m_aAnnotations = new ArrayList <JAnnotationUse> ();
509
510 final JAnnotationUse a = new JAnnotationUse (clazz);
511 m_aAnnotations.add (a);
512 return a;
513 }
514
515 @Nonnull
516 public JAnnotationUse annotate (@Nonnull final Class <? extends Annotation> clazz)
517 {
518 return annotate (m_aOwner.ref (clazz));
519 }
520
521 @Nonnull
522 public <W extends IJAnnotationWriter <?>> W annotate2 (@Nonnull final Class <W> clazz)
523 {
524 return TypedAnnotationWriter.create (clazz, this);
525 }
526
527 @Nonnull
528 public Collection <JAnnotationUse> annotations ()
529 {
530 if (m_aAnnotations == null)
531 m_aAnnotations = new ArrayList <JAnnotationUse> ();
532 return Collections.unmodifiableList (m_aAnnotations);
533 }
534
535
536
537
538 @Nonnull
539 File toPath (@Nonnull final File dir)
540 {
541 if (m_sName == null)
542 return dir;
543 return new File (dir, m_sName.replace ('.', File.separatorChar));
544 }
545
546 public void declare (@Nonnull final JFormatter f)
547 {
548 if (m_sName.length () != 0)
549 f.print ("package").print (m_sName).print (';').newline ();
550 }
551
552 public void generate (@Nonnull final JFormatter f)
553 {
554 f.print (m_sName);
555 }
556
557 void build (final AbstractCodeWriter src, final AbstractCodeWriter res) throws IOException
558 {
559
560 for (final JDefinedClass c : m_aClasses.values ())
561 {
562 if (c.isHidden ())
563 {
564
565 continue;
566 }
567
568 final JFormatter f = _createJavaSourceFileWriter (src, c.name ());
569 f.write (c);
570 f.close ();
571 }
572
573
574 if (m_aAnnotations != null || m_aJavaDoc != null)
575 {
576 final JFormatter f = _createJavaSourceFileWriter (src, "package-info");
577
578 if (m_aJavaDoc != null)
579 f.generable (m_aJavaDoc);
580
581
582 if (m_aAnnotations != null)
583 {
584 for (final JAnnotationUse a : m_aAnnotations)
585 f.generable (a).newline ();
586 }
587 f.declaration (this);
588
589 f.close ();
590 }
591
592
593 for (final AbstractJResourceFile rsrc : m_aResources)
594 {
595 final AbstractCodeWriter cw = rsrc.isResource () ? res : src;
596 final OutputStream os = new BufferedOutputStream (cw.openBinary (this, rsrc.name ()));
597 try
598 {
599 rsrc.build (os);
600 }
601 finally
602 {
603 os.close ();
604 }
605 }
606 }
607
608 boolean buildsErrorTypeRefs ()
609 {
610
611 for (final JDefinedClass c : m_aClasses.values ())
612 {
613 if (c.isHidden ())
614 {
615
616 continue;
617 }
618
619 if (JFormatter.containsErrorTypes (c))
620 return true;
621 }
622 return false;
623 }
624
625 int countArtifacts ()
626 {
627 int ret = 0;
628 for (final JDefinedClass c : m_aClasses.values ())
629 {
630 if (c.isHidden ())
631 {
632
633 continue;
634 }
635 ret++;
636 }
637
638 if (m_aAnnotations != null || m_aJavaDoc != null)
639 {
640
641 ret++;
642 }
643
644 ret += m_aResources.size ();
645
646 return ret;
647 }
648
649 @Nonnull
650 private JFormatter _createJavaSourceFileWriter (@Nonnull final AbstractCodeWriter src,
651 @Nonnull final String className) throws IOException
652 {
653 final Writer bw = new BufferedWriter (src.openSource (this, className + ".java"));
654 return new JFormatter (new PrintWriter (bw));
655 }
656 }