diff --git a/.gitignore b/.gitignore index 33b19b91..60c91d68 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ *.jar *.war *.ear +.DS_Store # Exception for gradle-wrapper !tools/gradlew-simplejava/wrapper.jar diff --git a/contributions/build.gradle b/contributions/build.gradle index 648b7bf8..16fd0d34 100644 --- a/contributions/build.gradle +++ b/contributions/build.gradle @@ -8,7 +8,7 @@ subprojects { apply plugin: 'eclipse' // If we don't set this, Eclipse will get confused - sourceCompatibility = '1.7' + sourceCompatibility = '10' // Use the maven repository to fetch dependencies repositories { diff --git a/contributions/jaxbComposition/build.gradle b/contributions/jaxbComposition/build.gradle index b7aa716f..5d53bf3c 100644 --- a/contributions/jaxbComposition/build.gradle +++ b/contributions/jaxbComposition/build.gradle @@ -6,7 +6,11 @@ version = '1.0.0' // Implementation specifics // This implementation uses JUnit for testing +// Added JAXB Dependencies, which are deprecated in JDK9+ dependencies { + compile('javax.activation:activation:1.1') + compile group: 'javax.xml.bind', name: 'jaxb-api', version: '2.4.0-b180830.0359' + compile group: 'org.glassfish.jaxb', name: 'jaxb-runtime', version: '2.4.0-b180830.0438' testCompile group: 'junit', name: 'junit', version: '4.11+' } // Generate model classes with xjc diff --git a/contributions/jaxbCompositionJava10/README.md b/contributions/jaxbCompositionJava10/README.md new file mode 100644 index 00000000..988b6054 --- /dev/null +++ b/contributions/jaxbCompositionJava10/README.md @@ -0,0 +1,102 @@ +== Headline == + +[[Object-XML mapping]] with [[Technology:JAXB|]] and [Language:Java|]]8 [[Namespace:Feature]]s + +== Characteristics == + +For the overall motivation of exercising [[Technology:JAXB]] see [[Contribution:jaxbComposition]]. This contribution is an overhaul of [[Contribution:jaxbComposition]] by applying new [[Namespace:Feature]]s introduced with [[Language:Java 8|]] such as [[Feature:Lambda Expressions]], [[Feature:Method references]] and [[Feature:Streams]]. The general idea behind this modernization is to update all necessary project dependencies, improve code readability and represent code in a more functional fashion by applying the aforementioned features. + +== Illustration == + +[[Feature:Open serialization]] is implemented using [[Technology:JAXB]] Un-/Marshaller. Furthermore the code has been reduced by employing Method chaining: + + + + public static Company deserializeCompany(File input) + throws JAXBException + { + initializeJaxbContext(); + return (Company) jaxbContext.createUnmarshaller().unmarshal(input); + } + + + + +public static void serializeCompany(File output, Company c) + throws JAXBException, + FileNotFoundException, + XMLStreamException + { + initializeJaxbContext(); + XMLStreamWriter writer = XMLOutputFactory.newInstance().createXMLStreamWriter(new FileOutputStream(output)); + jaxbContext.createMarshaller().marshal(c, writer); + } + +[[Feature:Total]] features [[Feature:Streams]] as a way of processing elements and [[Feature:Cut]] relies on Optionals for dealing with possible null values: + + + +public static double total(Department department) { + + double total = Optional.ofNullable(department.getManager()).map(Employee::getSalary).orElse(0.0); + + total += department.getDepartment() + .stream() + .map(dep -> total(dep)) + .reduce(0.0, Double::sum); + + return total += department.getEmployee() + .stream() + .map(emp -> emp.getSalary()) + .reduce(0.0, Double::sum); + } + + + + +public static void cut(Company company) { + Optional.ofNullable(company) + .map(Company::getDepartment) + .ifPresent(depts -> depts.forEach(Cut::cut)); + } + +Test cases are implemented for all [[Namespace:Feature]]s. + +== Relationships == + +For Object/XML mapping see [[Contribution:jaxbChoice]] (XSD with choice for different subunits), [[Contribution:jaxbComposition]] (XSD with object composition), [[Contribution:jaxbExtension]] (XSD with type extension) and [[Contribution:jaxbSubstitution]] (XSD with substitution groups). + +== Architecture == + +The contribution follows a standardized structure: +* inputs contains input files for tests +* src/main/java contains the following packages: +** org.softlang.company.features for implementations of [[Functional requirements]]. +* src/test/java contains the following packages: +** org.softlang.company.tests for [[Technology:JUnit]] test cases for [[Namespace:Feature]]s. + +== Usage == + +This contribution uses [[Technology:Gradle]] for building. [[Technology:Eclipse]] is supported. + +See https://github.com/101companies/101simplejava/blob/master/README.md + +== Metadata == + +* [[implements::Feature:Hierarchical company]] +* [[implements::Feature:Mapping]] +* [[implements::Feature:Open serialization]] +* [[implements::Feature:Total]] +* [[implements::Feature:Cut]] +* [[memberOf::Theme:Java mapping]] +* [[memberOf::Theme:XML programming]] +* [[uses::Language:Java]] +* [[uses::Language:XML]] +* [[uses::Language:XSD]] +* [[uses::Technology:JAXB]] +* [[uses::Technology:xjc]] +* [[uses::Technology:JUnit]] +* [[uses::Technology:Gradle]] +* [[uses::Concept:Lambdaware]] + + diff --git a/contributions/jaxbCompositionJava10/build.gradle b/contributions/jaxbCompositionJava10/build.gradle new file mode 100644 index 00000000..5d53bf3c --- /dev/null +++ b/contributions/jaxbCompositionJava10/build.gradle @@ -0,0 +1,35 @@ +apply plugin: 'java' +apply plugin: 'eclipse' + +group = 'org.softlang.company' +version = '1.0.0' + +// Implementation specifics +// This implementation uses JUnit for testing +// Added JAXB Dependencies, which are deprecated in JDK9+ +dependencies { + compile('javax.activation:activation:1.1') + compile group: 'javax.xml.bind', name: 'jaxb-api', version: '2.4.0-b180830.0359' + compile group: 'org.glassfish.jaxb', name: 'jaxb-runtime', version: '2.4.0-b180830.0438' + testCompile group: 'junit', name: 'junit', version: '4.11+' +} +// Generate model classes with xjc +task xjc(type: Exec) { + commandLine 'xjc' + args = ['inputs/Company.xsd', '-d', 'src/main/java', '-p' , 'org.softlang.company.xjc'] + doFirst { + mkdir 'src/main/java/org/softlang/company/xjc' + } +} +// Execute xjc before compiling Java code +compileJava { + dependsOn 'xjc' +} +// Additional cleanup for outputs and generated files +clean { + dependsOn cleanEclipse + doFirst { + delete 'outputs' + delete 'src/main/java/org/softlang/company/xjc' + } +} \ No newline at end of file diff --git a/contributions/jaxbCompositionJava10/inputs/Company.xsd b/contributions/jaxbCompositionJava10/inputs/Company.xsd new file mode 100644 index 00000000..16f3cfbf --- /dev/null +++ b/contributions/jaxbCompositionJava10/inputs/Company.xsd @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/contributions/jaxbCompositionJava10/inputs/sampleCompany.xml b/contributions/jaxbCompositionJava10/inputs/sampleCompany.xml new file mode 100644 index 00000000..fd698c12 --- /dev/null +++ b/contributions/jaxbCompositionJava10/inputs/sampleCompany.xml @@ -0,0 +1,55 @@ + + + ACME Corporation + + + Research + + Craig +
Redmond
+ 123456 +
+ + Erik +
Utrecht
+ 12345 +
+ + Ralf +
Koblenz
+ 1234 +
+
+ + + Development + + Ray +
Redmond
+ 234567 +
+ + Dev1 + + Klaus +
Boston
+ 23456 +
+ + Dev1.1 + + Karl +
Riga
+ 2345 +
+ + Joe +
Wifi City
+ 2344 +
+
+
+
+
diff --git a/contributions/jaxbCompositionJava10/src/main/java/org/softlang/company/features/Cut.java b/contributions/jaxbCompositionJava10/src/main/java/org/softlang/company/features/Cut.java new file mode 100644 index 00000000..7833fd07 --- /dev/null +++ b/contributions/jaxbCompositionJava10/src/main/java/org/softlang/company/features/Cut.java @@ -0,0 +1,29 @@ + +package org.softlang.company.features; + +import java.util.Optional; + +import org.softlang.company.xjc.*; + +public class Cut { + + public static void cut(Company company) { + Optional.ofNullable(company) + .map(Company::getDepartment) + .ifPresent(depts -> depts.forEach(Cut::cut)); + } + + public static void cut(Department department) { + Optional.ofNullable(department.getManager()) + .ifPresent(Cut::cut); + Optional.ofNullable(department.getDepartment()) + .ifPresent(dep -> dep.forEach(Cut::cut)); + Optional.ofNullable(department.getEmployee()) + .ifPresent(employee -> employee.forEach(Cut::cut)); + } + + public static void cut(Employee employee) { + employee.setSalary(employee.getSalary() / 2); + } + +} \ No newline at end of file diff --git a/contributions/jaxbCompositionJava10/src/main/java/org/softlang/company/features/Serialization.java b/contributions/jaxbCompositionJava10/src/main/java/org/softlang/company/features/Serialization.java new file mode 100644 index 00000000..f50a9f58 --- /dev/null +++ b/contributions/jaxbCompositionJava10/src/main/java/org/softlang/company/features/Serialization.java @@ -0,0 +1,44 @@ +package org.softlang.company.features; + +import org.softlang.company.xjc.Company; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; + +public class Serialization { + + private static JAXBContext jaxbContext; + + public static void initializeJaxbContext() + throws JAXBException + { + if (jaxbContext==null) + jaxbContext = + JAXBContext.newInstance("org.softlang.company.xjc"); + } + + public static Company deserializeCompany(File input) + throws JAXBException + { + initializeJaxbContext(); + return (Company) jaxbContext.createUnmarshaller().unmarshal(input); + } + + public static void serializeCompany(File output, Company c) + throws JAXBException, + FileNotFoundException, + XMLStreamException + { + initializeJaxbContext(); + XMLStreamWriter writer = XMLOutputFactory.newInstance().createXMLStreamWriter(new FileOutputStream(output)); + jaxbContext.createMarshaller().marshal(c, writer); + } + +} \ No newline at end of file diff --git a/contributions/jaxbCompositionJava10/src/main/java/org/softlang/company/features/Total.java b/contributions/jaxbCompositionJava10/src/main/java/org/softlang/company/features/Total.java new file mode 100644 index 00000000..f92e0ae9 --- /dev/null +++ b/contributions/jaxbCompositionJava10/src/main/java/org/softlang/company/features/Total.java @@ -0,0 +1,32 @@ + +package org.softlang.company.features; + +import java.util.Optional; + +import org.softlang.company.xjc.*; + +public class Total { + + public static double total(Company company) { + + return company.getDepartment() + .stream() + .map(depts -> total(depts)) + .reduce(0.0, Double::sum); + } + + public static double total(Department department) { + + double total = Optional.ofNullable(department.getManager()).map(Employee::getSalary).orElse(0.0); + + total += department.getDepartment() + .stream() + .map(dep -> total(dep)) + .reduce(0.0, Double::sum); + + return total += department.getEmployee() + .stream() + .map(emp -> emp.getSalary()) + .reduce(0.0, Double::sum); + } +} \ No newline at end of file diff --git a/contributions/jaxbCompositionJava10/src/test/java/org/softlang/company/tests/CutTest.java b/contributions/jaxbCompositionJava10/src/test/java/org/softlang/company/tests/CutTest.java new file mode 100644 index 00000000..7b21cda6 --- /dev/null +++ b/contributions/jaxbCompositionJava10/src/test/java/org/softlang/company/tests/CutTest.java @@ -0,0 +1,45 @@ +package org.softlang.company.tests; + +import static org.softlang.company.features.Serialization.*; +import org.softlang.company.features.Cut; +import org.softlang.company.features.Total; +import org.softlang.company.xjc.*; + +import javax.xml.bind.JAXBException; +import javax.xml.stream.XMLStreamException; + +import java.io.File; +import java.io.FileNotFoundException; + +import static org.junit.Assert.*; +import org.junit.Test; +import org.junit.Before; + +public class CutTest { + + private static String sampleCompany = "inputs" + File.separator + "sampleCompany.xml"; + private Company c; + + @Before + public void initCompany() throws JAXBException { + c = deserializeCompany(new File(sampleCompany)); + } + + @Test + public void testCut() + throws + JAXBException, + FileNotFoundException, + XMLStreamException + { + new File("outputs").mkdir(); + Cut.cut(c); + File tmp = new File("outputs" + File.separator + "cutCompany.tmp"); + serializeCompany(tmp, c); + c = deserializeCompany(tmp); + Double total = Total.total(c); + assertEquals(399747 / 2.0d, total, 0); + tmp.delete(); + } + +} \ No newline at end of file diff --git a/contributions/jaxbCompositionJava10/src/test/java/org/softlang/company/tests/SerializationTest.java b/contributions/jaxbCompositionJava10/src/test/java/org/softlang/company/tests/SerializationTest.java new file mode 100644 index 00000000..ec947563 --- /dev/null +++ b/contributions/jaxbCompositionJava10/src/test/java/org/softlang/company/tests/SerializationTest.java @@ -0,0 +1,43 @@ +package org.softlang.company.tests; + +import org.softlang.company.xjc.*; +import static org.softlang.company.features.Serialization.*; + +import javax.xml.bind.JAXBException; +import javax.xml.stream.XMLStreamException; + +import java.io.File; +import java.io.FileNotFoundException; + +import org.junit.Test; +import org.junit.Before; + +public class SerializationTest { + + private static String sampleCompany = "inputs" + File.separator + "sampleCompany.xml"; + private Company c; + + @Before + public void initCompany() throws JAXBException { + c = deserializeCompany(new File(sampleCompany)); + } + + @Test + public void testDeserialization() throws JAXBException { + deserializeCompany(new File(sampleCompany)); + } + + @Test + public void testSerialization() + throws + JAXBException, + FileNotFoundException, + XMLStreamException + { + new File("outputs").mkdir(); + File out = new File("outputs" + File.separator + "sampleCompany.tmp"); + serializeCompany(out, c); + c = deserializeCompany(out); + } + +} \ No newline at end of file diff --git a/contributions/jaxbCompositionJava10/src/test/java/org/softlang/company/tests/TotalTest.java b/contributions/jaxbCompositionJava10/src/test/java/org/softlang/company/tests/TotalTest.java new file mode 100644 index 00000000..1d3cd0e8 --- /dev/null +++ b/contributions/jaxbCompositionJava10/src/test/java/org/softlang/company/tests/TotalTest.java @@ -0,0 +1,38 @@ +package org.softlang.company.tests; + +import static org.softlang.company.features.Serialization.*; +import org.softlang.company.features.Total; +import org.softlang.company.xjc.*; + +import javax.xml.bind.JAXBException; +import javax.xml.stream.XMLStreamException; + +import java.io.File; +import java.io.FileNotFoundException; + +import static org.junit.Assert.*; +import org.junit.Test; +import org.junit.Before; + +public class TotalTest { + + private static String sampleCompany = "inputs" + File.separator + "sampleCompany.xml"; + private Company c; + + @Before + public void initCompany() throws JAXBException { + c = deserializeCompany(new File(sampleCompany)); + } + + @Test + public void testTotal() + throws + JAXBException, + FileNotFoundException, + XMLStreamException + { + double total = Total.total(c); + assertEquals(399747, total, 0); + } + +} \ No newline at end of file diff --git a/contributions/settings.gradle b/contributions/settings.gradle index b78bc2ee..f4d420e7 100644 --- a/contributions/settings.gradle +++ b/contributions/settings.gradle @@ -39,6 +39,7 @@ include 'javaTemplate' include 'javaVisitor' include 'jaxbChoice' include 'jaxbComposition' +include 'jaxbCompositionJava10' include 'jaxbExtension' include 'jaxbSubstitution' include 'jdom' diff --git a/tools/gradlew-simplejava/wrapper.properties b/tools/gradlew-simplejava/wrapper.properties index 71e03452..faed7457 100644 --- a/tools/gradlew-simplejava/wrapper.properties +++ b/tools/gradlew-simplejava/wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-1.12-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-bin.zip