11package io .ebean .querybean .generator ;
22
3+ import javax .annotation .processing .Filer ;
4+ import javax .annotation .processing .FilerException ;
35import javax .annotation .processing .Messager ;
46import javax .annotation .processing .ProcessingEnvironment ;
57import javax .lang .model .SourceVersion ;
1719import javax .lang .model .util .Elements ;
1820import javax .lang .model .util .Types ;
1921import javax .tools .Diagnostic ;
22+ import javax .tools .FileObject ;
23+ import javax .tools .JavaFileObject ;
24+ import java .io .FileNotFoundException ;
25+ import java .io .IOException ;
26+ import java .io .LineNumberReader ;
27+ import java .io .Reader ;
28+ import java .nio .file .NoSuchFileException ;
2029import java .util .ArrayList ;
30+ import java .util .HashSet ;
2131import java .util .List ;
32+ import java .util .Map ;
2233import java .util .Set ;
34+ import java .util .TreeMap ;
35+ import java .util .TreeSet ;
36+
37+ import static javax .tools .StandardLocation .CLASS_OUTPUT ;
2338
2439/**
2540 * Context for the source generation.
2641 */
2742class ProcessingContext implements Constants {
2843
44+ private final ProcessingEnvironment processingEnv ;
2945 private final String generatedSources ;
3046
3147 private final Types typeUtils ;
32-
48+ private final Filer filer ;
3349 private final Messager messager ;
34-
3550 private final Elements elementUtils ;
36-
3751 private final String generatedAnnotation ;
3852
3953 private final PropertyTypeMap propertyTypeMap = new PropertyTypeMap ();
4054
55+ private final ReadModuleInfo readModuleInfo ;
56+
57+ /**
58+ * All entity packages regardless of DB (for META-INF/ebean-generated-info.mf).
59+ */
60+ private final Set <String > allEntityPackages = new TreeSet <>();
61+
62+ /**
63+ * The DB name prefixed entities.
64+ */
65+ private final Set <String > prefixEntities = new TreeSet <>();
66+
67+ /**
68+ * Entity classes for the default database.
69+ */
70+ private final Set <String > dbEntities = new TreeSet <>();
71+
72+ /**
73+ * Entity classes for non default databases.
74+ */
75+ private final Map <String , Set <String >> otherDbEntities = new TreeMap <>();
76+
77+ /**
78+ * All loaded entities regardless of db (to detect ones we add back from loadedPrefixEntities).
79+ */
80+ private final Set <String > loaded = new HashSet <>();
81+
82+ /**
83+ * For partial compile the previous list of prefixed entity classes.
84+ */
85+ private List <String > loadedPrefixEntities ;
86+
87+ /**
88+ * The package for the generated ModuleInfoLoader.
89+ */
90+ private String factoryPackage ;
91+
4192 ProcessingContext (ProcessingEnvironment processingEnv ) {
93+ this .processingEnv = processingEnv ;
4294 this .typeUtils = processingEnv .getTypeUtils ();
95+ this .filer = processingEnv .getFiler ();
4396 this .messager = processingEnv .getMessager ();
4497 this .elementUtils = processingEnv .getElementUtils ();
98+
4599 boolean jdk8 = processingEnv .getSourceVersion ().compareTo (SourceVersion .RELEASE_8 ) <= 0 ;
46100 this .generatedAnnotation = generatedAnnotation (jdk8 );
47101 this .generatedSources = initGeneratedSources (processingEnv );
102+ this .readModuleInfo = new ReadModuleInfo (this );
48103 }
49104
50105 private String generatedAnnotation (boolean jdk8 ) {
@@ -274,8 +329,12 @@ private String packageAppend(String origPackage) {
274329 }
275330
276331 /**
277- * Log an error message .
332+ * Create a file writer for the given class name .
278333 */
334+ JavaFileObject createWriter (String factoryClassName , Element originatingElement ) throws IOException {
335+ return filer .createSourceFile (factoryClassName , originatingElement );
336+ }
337+
279338 void logError (Element e , String msg , Object ... args ) {
280339 messager .printMessage (Diagnostic .Kind .ERROR , String .format (msg , args ), e );
281340 }
@@ -294,4 +353,137 @@ boolean isGeneratedAvailable() {
294353 String getGeneratedAnnotation () {
295354 return generatedAnnotation ;
296355 }
356+
357+ void readModuleInfo () {
358+ String factory = loadMetaInfServices ();
359+ if (factory != null ) {
360+ TypeElement factoryType = elementUtils .getTypeElement (factory );
361+ if (factoryType != null ) {
362+ // previous prefixed entities to add back for partial compile
363+ loadedPrefixEntities = readModuleInfo .read (factoryType );
364+ }
365+ }
366+ }
367+
368+ /**
369+ * Register an entity with optional dbName.
370+ */
371+ void addEntity (String beanFullName , String dbName ) {
372+
373+ loaded .add (beanFullName );
374+ final String pkg = packageOf (beanFullName );
375+ if (pkg != null ) {
376+ allEntityPackages .add (pkg );
377+ }
378+ if (dbName != null ) {
379+ prefixEntities .add (dbName + ":" + beanFullName );
380+ otherDbEntities .computeIfAbsent (dbName , s -> new TreeSet <>()).add (beanFullName );
381+ } else {
382+ prefixEntities .add (beanFullName );
383+ dbEntities .add (beanFullName );
384+ updateFactoryPackage (pkg );
385+ }
386+ }
387+
388+ /**
389+ * Add back entity classes for partial compile.
390+ */
391+ int complete () {
392+
393+ int added = 0 ;
394+ if (loadedPrefixEntities != null ) {
395+ for (String oldPrefixEntity : loadedPrefixEntities ) {
396+ // maybe split as dbName:entityClass
397+ final String [] prefixEntityClass = oldPrefixEntity .split (":" );
398+
399+ String dbName = null ;
400+ String entityClass ;
401+ if (prefixEntityClass .length > 1 ) {
402+ dbName = prefixEntityClass [0 ];
403+ entityClass = prefixEntityClass [1 ];
404+ } else {
405+ entityClass = prefixEntityClass [0 ];
406+ }
407+ if (!loaded .contains (entityClass )) {
408+ addEntity (entityClass , dbName );
409+ added ++;
410+ }
411+ }
412+ }
413+ return added ;
414+ }
415+
416+ private String packageOf (String beanFullName ) {
417+ final int pos = beanFullName .lastIndexOf ('.' );
418+ if (pos > -1 ) {
419+ return beanFullName .substring (0 , pos );
420+ }
421+ return null ;
422+ }
423+
424+ private void updateFactoryPackage (String pkg ) {
425+ if (pkg != null && (factoryPackage == null || factoryPackage .length () > pkg .length ())) {
426+ factoryPackage = pkg ;
427+ }
428+ }
429+
430+ FileObject createMetaInfServicesWriter () throws IOException {
431+ return createMetaInfWriter (METAINF_SERVICES_MODULELOADER );
432+ }
433+
434+ FileObject createManifestWriter () throws IOException {
435+ return createMetaInfWriter (Constants .METAINF_MANIFEST );
436+ }
437+
438+ FileObject createMetaInfWriter (String target ) throws IOException {
439+ return filer .createResource (CLASS_OUTPUT , "" , target );
440+ }
441+
442+ Set <String > getPrefixEntities () {
443+ return prefixEntities ;
444+ }
445+
446+ Set <String > getDbEntities () {
447+ return dbEntities ;
448+ }
449+
450+ Map <String , Set <String >> getOtherDbEntities () {
451+ return otherDbEntities ;
452+ }
453+
454+
455+ Set <String > getAllEntityPackages () {
456+ return allEntityPackages ;
457+ }
458+
459+ String getFactoryPackage () {
460+ return factoryPackage != null ? factoryPackage : "unknown" ;
461+ }
462+
463+ /**
464+ * Return the class name of the generated ModuleInfoLoader
465+ * (such that we can read the current meta data for partial compile).
466+ */
467+ String loadMetaInfServices () {
468+ try {
469+ FileObject fileObject = processingEnv .getFiler ().getResource (CLASS_OUTPUT , "" , METAINF_SERVICES_MODULELOADER );
470+ if (fileObject != null ) {
471+ Reader reader = fileObject .openReader (true );
472+ LineNumberReader lineReader = new LineNumberReader (reader );
473+ String line = lineReader .readLine ();
474+ if (line != null ) {
475+ return line .trim ();
476+ }
477+ }
478+
479+ } catch (FileNotFoundException | NoSuchFileException e ) {
480+ // ignore - no services file yet
481+ } catch (FilerException e ) {
482+ logNote (null , "FilerException reading services file: " + e .getMessage ());
483+ } catch (Exception e ) {
484+ e .printStackTrace ();
485+ logError (null , "Error reading services file: " + e .getMessage ());
486+ }
487+ return null ;
488+ }
297489}
0 commit comments