-
Notifications
You must be signed in to change notification settings - Fork 5
Include XML parsing example in the Phone Bill archetype. #523
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| #set( $symbol_pound = '#' ) | ||
| #set( $symbol_dollar = '$' ) | ||
| #set( $symbol_escape = '\' ) | ||
| package ${package}; | ||
|
|
||
| import edu.pdx.cs.joy.ProjectXmlHelper; | ||
|
|
||
| public class PhoneBillXmlHelper extends ProjectXmlHelper { | ||
|
|
||
| /** | ||
| * The Public ID for the Phone Bill DTD | ||
| */ | ||
| protected static final String PUBLIC_ID = | ||
| "-//Joy of Coding at PSU//DTD Phone Bill//EN"; | ||
|
|
||
| protected PhoneBillXmlHelper() { | ||
| super(PUBLIC_ID, "phonebill.dtd"); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| #set( $symbol_pound = '#' ) | ||
| #set( $symbol_dollar = '$' ) | ||
| #set( $symbol_escape = '\' ) | ||
| <body> | ||
| <p>Contains the application classes for the Phone Bill project.</p> | ||
| </body> |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,55 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #set( $symbol_pound = '#' ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #set( $symbol_dollar = '$' ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #set( $symbol_escape = '\' ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package ${package}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.junit.jupiter.api.Test; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.xml.sax.SAXException; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.xml.sax.SAXParseException; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import javax.xml.parsers.DocumentBuilder; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import javax.xml.parsers.DocumentBuilderFactory; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import javax.xml.parsers.ParserConfigurationException; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.io.IOException; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import static org.junit.jupiter.api.Assertions.assertThrows; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class PhoneBillXmlHelperTest { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Test | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| void canParseValidXmlFile() throws ParserConfigurationException, IOException, SAXException { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PhoneBillXmlHelper helper = new PhoneBillXmlHelper(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+22
to
+23
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| DocumentBuilderFactory factory = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| DocumentBuilderFactory.newInstance(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| factory.setValidating(true); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| DocumentBuilder builder = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| factory.newDocumentBuilder(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| builder.setErrorHandler(helper); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| builder.setEntityResolver(helper); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| builder.parse(this.getClass().getResourceAsStream("valid-${artifactId}.xml")); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Test | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| void cantParseInvalidXmlFile() throws ParserConfigurationException { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| void cantParseInvalidXmlFile() throws ParserConfigurationException { | |
| void cannotParseInvalidXmlFile() throws ParserConfigurationException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh! I like that suggestion. But there are several places in the code base that have a cantParseInvalidXmlFile() method.
@copilot, please create a new PR that changes the name of the cantParseInvalidXmlFile() method to throwsExceptionWhenParsingInvalidXmlFile() across several occurrences: PhoneBillXmlHelperTest, AirlineXmlHelperTest, and AppointmentBookXmlHelperTest.
Copilot
AI
Nov 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] There are two consecutive blank lines after the helper instantiation. This appears inconsistent with typical Java formatting conventions which use a single blank line to separate logical blocks.
Copilot
AI
Nov 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The DocumentBuilderFactory and DocumentBuilder setup code (lines 24-31 and 41-48) is duplicated between the two test methods. Consider extracting this into a shared setup method (e.g., using @beforeeach or a private helper method) to improve maintainability.
| @Test | |
| void canParseValidXmlFile() throws ParserConfigurationException, IOException, SAXException { | |
| PhoneBillXmlHelper helper = new PhoneBillXmlHelper(); | |
| DocumentBuilderFactory factory = | |
| DocumentBuilderFactory.newInstance(); | |
| factory.setValidating(true); | |
| DocumentBuilder builder = | |
| factory.newDocumentBuilder(); | |
| builder.setErrorHandler(helper); | |
| builder.setEntityResolver(helper); | |
| builder.parse(this.getClass().getResourceAsStream("valid-${artifactId}.xml")); | |
| } | |
| @Test | |
| void cantParseInvalidXmlFile() throws ParserConfigurationException { | |
| PhoneBillXmlHelper helper = new PhoneBillXmlHelper(); | |
| DocumentBuilderFactory factory = | |
| DocumentBuilderFactory.newInstance(); | |
| factory.setValidating(true); | |
| DocumentBuilder builder = | |
| factory.newDocumentBuilder(); | |
| builder.setErrorHandler(helper); | |
| builder.setEntityResolver(helper); | |
| /** | |
| * Helper method to create and configure a DocumentBuilder with validation, | |
| * error handler, and entity resolver set to the provided helper. | |
| */ | |
| private DocumentBuilder createConfiguredBuilder(PhoneBillXmlHelper helper) | |
| throws ParserConfigurationException { | |
| DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); | |
| factory.setValidating(true); | |
| DocumentBuilder builder = factory.newDocumentBuilder(); | |
| builder.setErrorHandler(helper); | |
| builder.setEntityResolver(helper); | |
| return builder; | |
| } | |
| @Test | |
| void canParseValidXmlFile() throws ParserConfigurationException, IOException, SAXException { | |
| PhoneBillXmlHelper helper = new PhoneBillXmlHelper(); | |
| DocumentBuilder builder = createConfiguredBuilder(helper); | |
| builder.parse(this.getClass().getResourceAsStream("valid-${artifactId}.xml")); | |
| } | |
| @Test | |
| void cantParseInvalidXmlFile() throws ParserConfigurationException { | |
| PhoneBillXmlHelper helper = new PhoneBillXmlHelper(); | |
| DocumentBuilder builder = createConfiguredBuilder(helper); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ooh. Again, this is a great suggestion. But the like the previous suggested change, it ought to be made in several places in the codebase. (Admittedly, this pattern of creating DocumentBuilders is duplicated in the codebase.)
@copilot , please create a separate PR that refactors this duplicate code in the PhoneBillXmlHelperTest, AppointmentBookXmlHelperTest, and AirlineXmlHelperTest. Be sure to get the occurrences in both the "original" Maven projects and the "archetype" Maven projects.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| #set( $symbol_pound = '#' ) | ||
| #set( $symbol_dollar = '$' ) | ||
| #set( $symbol_escape = '\' ) | ||
| <body> | ||
| <p>Contains the test classes for the Phone Bill project.</p> | ||
| </body> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| #set( $symbol_pound = '#' ) | ||
| #set( $symbol_dollar = '$' ) | ||
| #set( $symbol_escape = '\' ) | ||
| <?xml version='1.0' encoding='us-ascii'?> | ||
|
|
||
| <!DOCTYPE phone-bill | ||
| PUBLIC "-//Joy of Coding at PSU//DTD Phone Bill//EN" "${artifactId}.dtd"> | ||
|
|
||
| <phone-bill> | ||
| <customer>Dave</customer> | ||
| <call> | ||
| <caller>503-245-2345</caller> | ||
| <!-- Missing callee --> | ||
| <start> | ||
| <date day="03" month="04" year="2025"/> | ||
| <time hour="9" minute="56"/> | ||
| </start> | ||
| <end> | ||
| <date day="03" month="04" year="2025"/> | ||
| <time hour="10" minute="39"/> | ||
| </end> | ||
| </call> | ||
| </phone-bill> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| #set( $symbol_pound = '#' ) | ||
| #set( $symbol_dollar = '$' ) | ||
| #set( $symbol_escape = '\' ) | ||
| <?xml version='1.0' encoding='us-ascii'?> | ||
|
|
||
| <!DOCTYPE phone-bill | ||
| PUBLIC "-//Joy of Coding at PSU//DTD Phone Bill//EN" "${artifactId}.dtd"> | ||
|
|
||
| <phone-bill> | ||
| <customer>Dave</customer> | ||
| <call> | ||
| <caller>503-245-2345</caller> | ||
| <callee>607-777-1369</callee> | ||
| <start> | ||
| <date day="03" month="04" year="2025"/> | ||
| <time hour="9" minute="56"/> | ||
| </start> | ||
| <end> | ||
| <date day="03" month="04" year="2025"/> | ||
| <!-- 43 minute call --> | ||
| <time hour="10" minute="39"/> | ||
| </end> | ||
| </call> | ||
| <call> | ||
| <caller>603-868-1932</caller> | ||
| <callee>765-497-8254</callee> | ||
| <start> | ||
| <date day="10" month="7" year="2025"/> | ||
| <time hour="5" minute="27"/> | ||
| </start> | ||
| <end> | ||
| <date day="10" month="7" year="2025"/> | ||
| <time hour="6" minute="04"/> | ||
| </end> | ||
| </call> | ||
| </phone-bill> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The DTD filename is hardcoded as "phonebill.dtd", but the XML files reference "${artifactId}.dtd" (line 7 in both XML files). This mismatch will cause the DTD resolution to fail. The filename should be a template variable that matches the XML reference, or the XML files should use the hardcoded filename.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch. At one point I had the name of the the DTD as
${artifactId}.dtd, but it caused the integration tests to fail. The integration tests use artifacts names like "basic" and "javadoc". And, clearly, there isn't a "basic.dtd" file.So, this doesn't seem like the right change to me.
You make a good point about the names of the testing .xml files having $artifactId in them.
I think those work out okay because they are also referenced by $artifactId in the unit testing code.