1919import  org .agrona .MutableDirectBuffer ;
2020import  org .agrona .Strings ;
2121import  org .agrona .Verify ;
22- import  org .agrona .generation .OutputManager ;
22+ import  org .agrona .generation .DynamicPackageOutputManager ;
2323import  org .agrona .sbe .*;
2424import  uk .co .real_logic .sbe .PrimitiveType ;
2525import  uk .co .real_logic .sbe .generation .CodeGenerator ;
2929import  java .io .IOException ;
3030import  java .io .Writer ;
3131import  java .util .ArrayList ;
32+ import  java .util .Collections ;
3233import  java .util .Formatter ;
34+ import  java .util .HashSet ;
3335import  java .util .List ;
36+ import  java .util .Set ;
3437import  java .util .function .Function ;
3538
3639import  static  uk .co .real_logic .sbe .SbeTool .JAVA_INTERFACE_PACKAGE ;
@@ -58,16 +61,43 @@ enum CodecType
5861 private  static  final  String  PACKAGE_INFO  = "package-info" ;
5962 private  static  final  String  BASE_INDENT  = "" ;
6063 private  static  final  String  INDENT  = " " ;
64+  private  static  final  Set <String > PACKAGES_EMPTY_SET  = Collections .emptySet ();
6165
6266 private  final  Ir  ir ;
63-  private  final  OutputManager  outputManager ;
67+  private  final  DynamicPackageOutputManager  outputManager ;
6468 private  final  String  fqMutableBuffer ;
6569 private  final  String  mutableBuffer ;
6670 private  final  String  fqReadOnlyBuffer ;
6771 private  final  String  readOnlyBuffer ;
6872 private  final  boolean  shouldGenerateGroupOrderAnnotation ;
6973 private  final  boolean  shouldGenerateInterfaces ;
7074 private  final  boolean  shouldDecodeUnknownEnumValues ;
75+  private  final  boolean  shouldSupportTypesPackageNames ;
76+  private  final  Set <String > packageNameByTypes  = new  HashSet <>();
77+ 
78+  /** 
79+  * Create a new Java language {@link CodeGenerator}. Generator support for types in their own package is disabled. 
80+  * 
81+  * @param ir for the messages and types. 
82+  * @param mutableBuffer implementation used for mutating underlying buffers. 
83+  * @param readOnlyBuffer implementation used for reading underlying buffers. 
84+  * @param shouldGenerateGroupOrderAnnotation in the codecs. 
85+  * @param shouldGenerateInterfaces for common methods. 
86+  * @param shouldDecodeUnknownEnumValues generate support for unknown enum values when decoding. 
87+  * @param outputManager for generating the codecs to. 
88+  */ 
89+  public  JavaGenerator (
90+  final  Ir  ir ,
91+  final  String  mutableBuffer ,
92+  final  String  readOnlyBuffer ,
93+  final  boolean  shouldGenerateGroupOrderAnnotation ,
94+  final  boolean  shouldGenerateInterfaces ,
95+  final  boolean  shouldDecodeUnknownEnumValues ,
96+  final  DynamicPackageOutputManager  outputManager )
97+  {
98+  this (ir , mutableBuffer , readOnlyBuffer , shouldGenerateGroupOrderAnnotation , shouldGenerateInterfaces ,
99+  shouldDecodeUnknownEnumValues , false , outputManager );
100+  }
71101
72102 /** 
73103 * Create a new Java language {@link CodeGenerator}. 
@@ -78,6 +108,7 @@ enum CodecType
78108 * @param shouldGenerateGroupOrderAnnotation in the codecs. 
79109 * @param shouldGenerateInterfaces for common methods. 
80110 * @param shouldDecodeUnknownEnumValues generate support for unknown enum values when decoding. 
111+  * @param shouldSupportTypesPackageNames generator support for types in their own package. 
81112 * @param outputManager for generating the codecs to. 
82113 */ 
83114 public  JavaGenerator (
@@ -87,12 +118,14 @@ public JavaGenerator(
87118 final  boolean  shouldGenerateGroupOrderAnnotation ,
88119 final  boolean  shouldGenerateInterfaces ,
89120 final  boolean  shouldDecodeUnknownEnumValues ,
90-  final  OutputManager  outputManager )
121+  final  boolean  shouldSupportTypesPackageNames ,
122+  final  DynamicPackageOutputManager  outputManager )
91123 {
92124 Verify .notNull (ir , "ir" );
93125 Verify .notNull (outputManager , "outputManager" );
94126
95127 this .ir  = ir ;
128+  this .shouldSupportTypesPackageNames  = shouldSupportTypesPackageNames ;
96129 this .outputManager  = outputManager ;
97130
98131 this .mutableBuffer  = validateBufferImplementation (mutableBuffer , MutableDirectBuffer .class );
@@ -144,11 +177,36 @@ public void generateTypeStubs() throws IOException
144177 }
145178 }
146179
180+  /** 
181+  * Register the types explicit package - if set and should be supported. 
182+  * 
183+  * @param token the 0-th token of the type. 
184+  * @param ir the intermediate representation. 
185+  * @return the overridden package name of the type if set and supported, or {@link Ir#applicableNamespace()}. 
186+  */ 
187+  private  String  registerTypesPackageName (final  Token  token , final  Ir  ir )
188+  {
189+  if  (!shouldSupportTypesPackageNames )
190+  {
191+  return  ir .applicableNamespace ();
192+  }
193+ 
194+  if  (token .packageName () != null )
195+  {
196+  packageNameByTypes .add (token .packageName ());
197+  outputManager .setPackageName (token .packageName ());
198+  return  token .packageName ();
199+  }
200+ 
201+  return  ir .applicableNamespace ();
202+  }
203+ 
147204 /** 
148205 * {@inheritDoc} 
149206 */ 
150207 public  void  generate () throws  IOException 
151208 {
209+  packageNameByTypes .clear ();
152210 generatePackageInfo ();
153211 generateTypeStubs ();
154212 generateMessageHeaderStub ();
@@ -1188,10 +1246,12 @@ private void generateBitSet(final List<Token> tokens) throws IOException
11881246 final  List <Token > choiceList  = tokens .subList (1 , tokens .size () - 1 );
11891247 final  String  implementsString  = implementsInterface (Flyweight .class .getSimpleName ());
11901248
1249+  registerTypesPackageName (token , ir );
11911250 try  (Writer  out  = outputManager .createOutput (decoderName ))
11921251 {
11931252 final  Encoding  encoding  = token .encoding ();
1194-  generateFixedFlyweightHeader (out , token , decoderName , implementsString , readOnlyBuffer , fqReadOnlyBuffer );
1253+  generateFixedFlyweightHeader (
1254+  out , token , decoderName , implementsString , readOnlyBuffer , fqReadOnlyBuffer , PACKAGES_EMPTY_SET );
11951255 out .append (generateChoiceIsEmpty (encoding .primitiveType ()));
11961256
11971257 new  Formatter (out ).format (
@@ -1208,9 +1268,11 @@ private void generateBitSet(final List<Token> tokens) throws IOException
12081268 out .append ("}\n " );
12091269 }
12101270
1271+  registerTypesPackageName (token , ir );
12111272 try  (Writer  out  = outputManager .createOutput (encoderName ))
12121273 {
1213-  generateFixedFlyweightHeader (out , token , encoderName , implementsString , mutableBuffer , fqMutableBuffer );
1274+  generateFixedFlyweightHeader (
1275+  out , token , encoderName , implementsString , mutableBuffer , fqMutableBuffer , PACKAGES_EMPTY_SET );
12141276 generateChoiceClear (out , encoderName , token );
12151277 generateChoiceEncoders (out , encoderName , choiceList );
12161278 out .append ("}\n " );
@@ -1223,9 +1285,10 @@ private void generateFixedFlyweightHeader(
12231285 final  String  typeName ,
12241286 final  String  implementsString ,
12251287 final  String  buffer ,
1226-  final  String  fqBuffer ) throws  IOException 
1288+  final  String  fqBuffer ,
1289+  final  Set <String > importedTypesPackages ) throws  IOException 
12271290 {
1228-  out .append (generateFileHeader (ir . applicableNamespace () , fqBuffer ));
1291+  out .append (generateFileHeader (registerTypesPackageName ( token ,  ir ),  importedTypesPackages , fqBuffer ));
12291292 out .append (generateDeclaration (typeName , implementsString , token ));
12301293 out .append (generateFixedFlyweightCode (typeName , token .encodedLength (), buffer ));
12311294 }
@@ -1236,9 +1299,10 @@ private void generateCompositeFlyweightHeader(
12361299 final  Writer  out ,
12371300 final  String  buffer ,
12381301 final  String  fqBuffer ,
1239-  final  String  implementsString ) throws  IOException 
1302+  final  String  implementsString ,
1303+  final  Set <String > importedTypesPackages ) throws  IOException 
12401304 {
1241-  out .append (generateFileHeader (ir . applicableNamespace () , fqBuffer ));
1305+  out .append (generateFileHeader (registerTypesPackageName ( token ,  ir ),  importedTypesPackages , fqBuffer ));
12421306 out .append (generateDeclaration (typeName , implementsString , token ));
12431307 out .append (generateFixedFlyweightCode (typeName , token .encodedLength (), buffer ));
12441308 }
@@ -1249,10 +1313,11 @@ private void generateEnum(final List<Token> tokens) throws IOException
12491313 final  String  enumName  = formatClassName (enumToken .applicableTypeName ());
12501314 final  Encoding  encoding  = enumToken .encoding ();
12511315 final  String  nullVal  = encoding .applicableNullValue ().toString ();
1316+  final  String  packageName  = registerTypesPackageName (enumToken , ir );
12521317
12531318 try  (Writer  out  = outputManager .createOutput (enumName ))
12541319 {
1255-  out .append (generateEnumFileHeader (ir . applicableNamespace () ));
1320+  out .append (generateEnumFileHeader (packageName ));
12561321 out .append (generateEnumDeclaration (enumName , enumToken ));
12571322
12581323 final  List <Token > valuesList  = tokens .subList (1 , tokens .size () - 1 );
@@ -1272,11 +1337,14 @@ private void generateComposite(final List<Token> tokens) throws IOException
12721337 final  String  decoderName  = decoderName (compositeName );
12731338 final  String  encoderName  = encoderName (compositeName );
12741339
1340+  registerTypesPackageName (token , ir );
1341+  final  Set <String > importedTypesPackages  = scanPackagesToImport (tokens );
1342+ 
12751343 try  (Writer  out  = outputManager .createOutput (decoderName ))
12761344 {
12771345 final  String  implementsString  = implementsInterface (CompositeDecoderFlyweight .class .getSimpleName ());
12781346 generateCompositeFlyweightHeader (
1279-  token , decoderName , out , readOnlyBuffer , fqReadOnlyBuffer , implementsString );
1347+  token , decoderName , out , readOnlyBuffer , fqReadOnlyBuffer , implementsString ,  importedTypesPackages );
12801348
12811349 for  (int  i  = 1 , end  = tokens .size () - 1 ; i  < end ;)
12821350 {
@@ -1320,10 +1388,12 @@ private void generateComposite(final List<Token> tokens) throws IOException
13201388 out .append ("}\n " );
13211389 }
13221390
1391+  registerTypesPackageName (token , ir );
13231392 try  (Writer  out  = outputManager .createOutput (encoderName ))
13241393 {
13251394 final  String  implementsString  = implementsInterface (CompositeEncoderFlyweight .class .getSimpleName ());
1326-  generateCompositeFlyweightHeader (token , encoderName , out , mutableBuffer , fqMutableBuffer , implementsString );
1395+  generateCompositeFlyweightHeader (
1396+  token , encoderName , out , mutableBuffer , fqMutableBuffer , implementsString , importedTypesPackages );
13271397
13281398 for  (int  i  = 1 , end  = tokens .size () - 1 ; i  < end ;)
13291399 {
@@ -1365,6 +1435,32 @@ private void generateComposite(final List<Token> tokens) throws IOException
13651435 }
13661436 }
13671437
1438+  private  Set <String > scanPackagesToImport (final  List <Token > tokens )
1439+  {
1440+  if  (!shouldSupportTypesPackageNames )
1441+  {
1442+  return  PACKAGES_EMPTY_SET ;
1443+  }
1444+ 
1445+  final  Set <String > packagesToImport  = new  HashSet <>();
1446+ 
1447+  for  (int  i  = 1 , limit  = tokens .size () - 1 ; i  < limit ; i ++)
1448+  {
1449+  final  Token  typeToken  = tokens .get (i );
1450+  if  (typeToken .signal () == Signal .BEGIN_ENUM  ||
1451+  typeToken .signal () == Signal .BEGIN_SET  ||
1452+  typeToken .signal () == Signal .BEGIN_COMPOSITE )
1453+  {
1454+  if  (typeToken .packageName () != null )
1455+  {
1456+  packagesToImport .add (typeToken .packageName ());
1457+  }
1458+  }
1459+  }
1460+ 
1461+  return  packagesToImport ;
1462+  }
1463+ 
13681464 private  void  generateChoiceClear (final  Appendable  out , final  String  bitSetClassName , final  Token  token )
13691465 throws  IOException 
13701466 {
@@ -1550,6 +1646,26 @@ private CharSequence generateEnumLookupMethod(final List<Token> tokens, final St
15501646 return  sb ;
15511647 }
15521648
1649+  private  StringBuilder  generateImportStatements (final  Set <String > packages , final  String  currentPackage )
1650+  {
1651+  final  StringBuilder  importStatements  = new  StringBuilder ();
1652+ 
1653+  for  (final  String  candidatePackage  : packages )
1654+  {
1655+  if  (!candidatePackage .equals (currentPackage ))
1656+  {
1657+  importStatements .append ("import " ).append (candidatePackage ).append (".*;\n " );
1658+  }
1659+  }
1660+ 
1661+  if  (importStatements .length () > 0 )
1662+  {
1663+  importStatements .append ("\n \n " );
1664+  }
1665+ 
1666+  return  importStatements ;
1667+  }
1668+ 
15531669 private  String  interfaceImportLine ()
15541670 {
15551671 if  (!shouldGenerateInterfaces )
@@ -1560,25 +1676,32 @@ private String interfaceImportLine()
15601676 return  "import "  + JAVA_INTERFACE_PACKAGE  + ".*;\n \n " ;
15611677 }
15621678
1563-  private  CharSequence  generateFileHeader (final  String  packageName , final  String  fqBuffer )
1679+ 
1680+  private  CharSequence  generateFileHeader (final  String  packageName , final  Set <String > importedTypesPackages ,
1681+  final  String  fqBuffer )
15641682 {
1565-  return 
1566-  "/* Generated SBE (Simple Binary Encoding) message codec. */\n "  +
1683+  final  StringBuilder  importStatements  = generateImportStatements (importedTypesPackages , packageName );
1684+ 
1685+  return  "/* Generated SBE (Simple Binary Encoding) message codec. */\n "  +
15671686 "package "  + packageName  + ";\n \n "  +
15681687 "import "  + fqBuffer  + ";\n "  +
1569-  interfaceImportLine ();
1688+  interfaceImportLine () +
1689+  importStatements ;
15701690 }
15711691
15721692 private  CharSequence  generateMainHeader (
15731693 final  String  packageName , final  CodecType  codecType , final  boolean  hasVarData )
15741694 {
1695+  final  StringBuilder  importStatements  = generateImportStatements (packageNameByTypes , packageName );
1696+ 
15751697 if  (fqMutableBuffer .equals (fqReadOnlyBuffer ))
15761698 {
15771699 return 
15781700 "/* Generated SBE (Simple Binary Encoding) message codec. */\n "  +
15791701 "package "  + packageName  + ";\n \n "  +
15801702 "import "  + fqMutableBuffer  + ";\n "  +
1581-  interfaceImportLine ();
1703+  interfaceImportLine () +
1704+  importStatements ;
15821705 }
15831706 else 
15841707 {
@@ -1590,7 +1713,8 @@ private CharSequence generateMainHeader(
15901713 "package "  + packageName  + ";\n \n "  +
15911714 (hasMutableBuffer  ? "import "  + fqMutableBuffer  + ";\n "  : "" ) +
15921715 (hasReadOnlyBuffer  ? "import "  + fqReadOnlyBuffer  + ";\n "  : "" ) +
1593-  interfaceImportLine ();
1716+  interfaceImportLine () +
1717+  importStatements ;
15941718 }
15951719 }
15961720
@@ -3759,13 +3883,6 @@ private String decoderName(final String className)
37593883
37603884 private  String  implementsInterface (final  String  interfaceName )
37613885 {
3762-  if  (!shouldGenerateInterfaces )
3763-  {
3764-  return  "" ;
3765-  }
3766-  else 
3767-  {
3768-  return  " implements "  + interfaceName ;
3769-  }
3886+  return  shouldGenerateInterfaces  ? " implements "  + interfaceName  : "" ;
37703887 }
37713888}
0 commit comments