Skip to content

Commit 4d37f33

Browse files
authored
[Java] DTOs respect the optional package field in the schema definition (#1022)
* [Java] DTOs respect the optional package field in the schema definition * [Java] checkstyle
1 parent ae002c2 commit 4d37f33

File tree

6 files changed

+126
-16
lines changed

6 files changed

+126
-16
lines changed

sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,20 +52,24 @@ public CodeGenerator newInstance(final Ir ir, final String outputDir)
5252
{
5353
final JavaOutputManager outputManager = new JavaOutputManager(outputDir, ir.applicableNamespace());
5454

55+
final boolean shouldSupportTypesPackageNames = Boolean.getBoolean(TYPES_PACKAGE_OVERRIDE);
5556
final JavaGenerator codecGenerator = new JavaGenerator(
5657
ir,
5758
System.getProperty(JAVA_ENCODING_BUFFER_TYPE, JAVA_DEFAULT_ENCODING_BUFFER_TYPE),
5859
System.getProperty(JAVA_DECODING_BUFFER_TYPE, JAVA_DEFAULT_DECODING_BUFFER_TYPE),
5960
Boolean.getBoolean(JAVA_GROUP_ORDER_ANNOTATION),
6061
Boolean.getBoolean(JAVA_GENERATE_INTERFACES),
6162
Boolean.getBoolean(DECODE_UNKNOWN_ENUM_VALUES),
62-
Boolean.getBoolean(TYPES_PACKAGE_OVERRIDE),
63+
shouldSupportTypesPackageNames,
6364
precedenceChecks(),
6465
outputManager);
6566

6667
if (Boolean.getBoolean(JAVA_GENERATE_DTOS))
6768
{
68-
final JavaDtoGenerator dtoGenerator = new JavaDtoGenerator(ir, outputManager);
69+
final JavaDtoGenerator dtoGenerator = new JavaDtoGenerator(
70+
ir,
71+
shouldSupportTypesPackageNames,
72+
outputManager);
6973
return () ->
7074
{
7175
codecGenerator.generate();

sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
import static uk.co.real_logic.sbe.ir.GenerationUtil.collectVarData;
4242

4343
/**
44-
* DTO generator for the CSharp programming language.
44+
* DTO generator for the C++ programming language.
4545
*/
4646
public class CppDtoGenerator implements CodeGenerator
4747
{
@@ -52,7 +52,7 @@ public class CppDtoGenerator implements CodeGenerator
5252
private final OutputManager outputManager;
5353

5454
/**
55-
* Create a new C# DTO {@link CodeGenerator}.
55+
* Create a new C++ DTO {@link CodeGenerator}.
5656
*
5757
* @param ir for the messages and types.
5858
* @param outputManager for generating the DTOs to.

sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java

Lines changed: 75 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,14 @@
2424
import uk.co.real_logic.sbe.ir.Token;
2525
import org.agrona.LangUtil;
2626
import org.agrona.Verify;
27-
import org.agrona.generation.OutputManager;
27+
import org.agrona.generation.DynamicPackageOutputManager;
2828

2929
import java.io.IOException;
3030
import java.io.Writer;
3131
import java.util.ArrayList;
32+
import java.util.HashSet;
3233
import java.util.List;
34+
import java.util.Set;
3335
import java.util.function.Predicate;
3436

3537
import static uk.co.real_logic.sbe.generation.Generators.toLowerFirstChar;
@@ -49,23 +51,48 @@ public class JavaDtoGenerator implements CodeGenerator
4951
private static final String BASE_INDENT = "";
5052

5153
private final Ir ir;
52-
private final OutputManager outputManager;
54+
private final DynamicPackageOutputManager outputManager;
55+
private final boolean shouldSupportTypesPackageNames;
56+
private final Set<String> packageNameByTypes = new HashSet<>();
5357

5458
/**
55-
* Create a new C# DTO {@link CodeGenerator}.
59+
* Create a new Java DTO {@link CodeGenerator}.
5660
*
57-
* @param ir for the messages and types.
58-
* @param outputManager for generating the DTOs to.
61+
* @param ir for the messages and types.
62+
* @param shouldSupportTypesPackageNames generator support for types in their own package.
63+
* @param outputManager for generating the DTOs to.
5964
*/
60-
public JavaDtoGenerator(final Ir ir, final OutputManager outputManager)
65+
public JavaDtoGenerator(
66+
final Ir ir,
67+
final boolean shouldSupportTypesPackageNames,
68+
final DynamicPackageOutputManager outputManager)
6169
{
70+
this.shouldSupportTypesPackageNames = shouldSupportTypesPackageNames;
6271
Verify.notNull(ir, "ir");
6372
Verify.notNull(outputManager, "outputManager");
6473

6574
this.ir = ir;
6675
this.outputManager = outputManager;
6776
}
6877

78+
/**
79+
* Fetch the type's explicit package - if set and should be supported.
80+
*
81+
* @param token the 0-th token of the type.
82+
* @param ir the intermediate representation.
83+
* @return the overridden package name of the type if set and supported, or {@link Ir#applicableNamespace()}.
84+
*/
85+
private String fetchTypesPackageName(final Token token, final Ir ir)
86+
{
87+
if (shouldSupportTypesPackageNames && token.packageName() != null)
88+
{
89+
outputManager.setPackageName(token.packageName());
90+
return token.packageName();
91+
}
92+
93+
return ir.applicableNamespace();
94+
}
95+
6996
/**
7097
* {@inheritDoc}
7198
*/
@@ -110,9 +137,10 @@ public void generate() throws IOException
110137
generateDisplay(classBuilder, encoderClassName, "computeEncodedLength()",
111138
BASE_INDENT + INDENT);
112139

140+
final String packageName = fetchTypesPackageName(msgToken, ir);
113141
try (Writer out = outputManager.createOutput(dtoClassName))
114142
{
115-
out.append(generateDtoFileHeader(ir.applicableNamespace()));
143+
out.append(generateDtoFileHeader(packageName));
116144
out.append("import org.agrona.DirectBuffer;\n");
117145
out.append("import org.agrona.MutableDirectBuffer;\n");
118146
out.append("import org.agrona.concurrent.UnsafeBuffer;\n\n");
@@ -1582,6 +1610,19 @@ private static String formatDtoClassName(final String name)
15821610

15831611
private void generateDtosForTypes() throws IOException
15841612
{
1613+
if (shouldSupportTypesPackageNames)
1614+
{
1615+
for (final List<Token> tokens : ir.types())
1616+
{
1617+
final String packageName = tokens.get(0).packageName();
1618+
1619+
if (packageName != null)
1620+
{
1621+
packageNameByTypes.add(packageName);
1622+
}
1623+
}
1624+
}
1625+
15851626
for (final List<Token> tokens : ir.types())
15861627
{
15871628
switch (tokens.get(0).signal())
@@ -1607,10 +1648,11 @@ private void generateComposite(final List<Token> tokens) throws IOException
16071648
final String encoderClassName = encoderName(name);
16081649
final String decoderClassName = decoderName(name);
16091650

1651+
final String packageName = fetchTypesPackageName(tokens.get(0), ir);
16101652
try (Writer out = outputManager.createOutput(className))
16111653
{
16121654
final List<Token> compositeTokens = tokens.subList(1, tokens.size() - 1);
1613-
out.append(generateDtoFileHeader(ir.applicableNamespace()));
1655+
out.append(generateDtoFileHeader(packageName));
16141656
out.append("import org.agrona.DirectBuffer;\n");
16151657
out.append("import org.agrona.MutableDirectBuffer;\n");
16161658
out.append("import org.agrona.concurrent.UnsafeBuffer;\n\n");
@@ -1638,10 +1680,11 @@ private void generateChoiceSet(final List<Token> tokens) throws IOException
16381680
final String encoderClassName = encoderName(name);
16391681
final String decoderClassName = decoderName(name);
16401682

1683+
final String packageName = fetchTypesPackageName(tokens.get(0), ir);
16411684
try (Writer out = outputManager.createOutput(className))
16421685
{
16431686
final List<Token> setTokens = tokens.subList(1, tokens.size() - 1);
1644-
out.append(generateDtoFileHeader(ir.applicableNamespace()));
1687+
out.append(generateDtoFileHeader(packageName));
16451688
out.append(generateDocumentation(BASE_INDENT, tokens.get(0)));
16461689

16471690
final ClassBuilder classBuilder = new ClassBuilder(className, BASE_INDENT, "public final");
@@ -1795,13 +1838,35 @@ private void generateCompositePropertyElements(
17951838
}
17961839
}
17971840

1798-
private static CharSequence generateDtoFileHeader(final String packageName)
1841+
private static StringBuilder generateImportStatements(final Set<String> packages, final String currentPackage)
1842+
{
1843+
final StringBuilder importStatements = new StringBuilder();
1844+
1845+
for (final String candidatePackage : packages)
1846+
{
1847+
if (!candidatePackage.equals(currentPackage))
1848+
{
1849+
importStatements.append("import ").append(candidatePackage).append(".*;\n");
1850+
}
1851+
}
1852+
1853+
if (!importStatements.isEmpty())
1854+
{
1855+
importStatements.append("\n\n");
1856+
}
1857+
1858+
return importStatements;
1859+
}
1860+
1861+
private CharSequence generateDtoFileHeader(final String packageName)
17991862
{
18001863
final StringBuilder sb = new StringBuilder();
18011864

18021865
sb.append("/* Generated SBE (Simple Binary Encoding) message DTO */\n");
18031866
sb.append("package ").append(packageName).append(";\n\n");
18041867

1868+
sb.append(generateImportStatements(packageNameByTypes, packageName));
1869+
18051870
return sb;
18061871
}
18071872

sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtos.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import uk.co.real_logic.sbe.generation.TargetCodeGenerator;
2121
import uk.co.real_logic.sbe.ir.Ir;
2222

23+
import static uk.co.real_logic.sbe.SbeTool.TYPES_PACKAGE_OVERRIDE;
24+
2325
/**
2426
* {@link CodeGenerator} factory for Java DTOs.
2527
*/
@@ -30,6 +32,9 @@ public class JavaDtos implements TargetCodeGenerator
3032
*/
3133
public CodeGenerator newInstance(final Ir ir, final String outputDir)
3234
{
33-
return new JavaDtoGenerator(ir, new JavaOutputManager(outputDir, ir.applicableNamespace()));
35+
return new JavaDtoGenerator(
36+
ir,
37+
Boolean.getBoolean(TYPES_PACKAGE_OVERRIDE),
38+
new JavaOutputManager(outputDir, ir.applicableNamespace()));
3439
}
3540
}

sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ void javaDtoEncodeShouldBeTheInverseOfDtoDecode(
8787
outputManager)
8888
.generate();
8989

90-
new JavaDtoGenerator(encodedMessage.ir(), outputManager)
90+
new JavaDtoGenerator(encodedMessage.ir(), false, outputManager)
9191
.generate();
9292
}
9393
catch (final Exception generationException)

sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,42 @@ void shouldCreateTypesInSamePackageIfSupportDisabled() throws Exception
601601
}
602602
}
603603

604+
@Test
605+
void dtosShouldReferenceTypesInDifferentPackages() throws Exception
606+
{
607+
try (InputStream in = Tests.getLocalResource("explicit-package-test-schema.xml"))
608+
{
609+
final ParserOptions options = ParserOptions.builder().stopOnError(true).build();
610+
final MessageSchema schema = parse(in, options);
611+
final IrGenerator irg = new IrGenerator();
612+
ir = irg.generate(schema);
613+
614+
outputManager.clear();
615+
outputManager.setPackageName(ir.applicableNamespace());
616+
617+
final JavaGenerator generator = new JavaGenerator(
618+
ir, BUFFER_NAME, READ_ONLY_BUFFER_NAME, false, false, false, true, outputManager
619+
);
620+
generator.generate();
621+
622+
final JavaDtoGenerator javaDtoGenerator = new JavaDtoGenerator(ir, true, outputManager);
623+
javaDtoGenerator.generate();
624+
625+
final Map<String, CharSequence> sources = outputManager.getSources();
626+
assertNotNull(sources.get("test.message.schema.TestMessageDto"));
627+
assertNotNull(sources.get("test.message.schema.MessageHeaderDto"));
628+
assertNotNull(sources.get("test.message.schema.common.CarDto"));
629+
assertNotNull(sources.get("test.message.schema.common.EngineDto"));
630+
assertNotNull(sources.get("outside.schema.FuelSpecDto"));
631+
assertNotNull(sources.get("outside.schema.DaysDto"));
632+
assertNotNull(sources.get("outside.schema.FuelTypeDto"));
633+
634+
assertNotNull(compile("test.message.schema.TestMessageDto"));
635+
assertNotNull(compile("test.message.schema.common.CarDto"));
636+
assertNotNull(compile("outside.schema.FuelSpecDto"));
637+
}
638+
}
639+
604640
@ParameterizedTest
605641
@CsvSource(
606642
{

0 commit comments

Comments
 (0)