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