Project dependencies and Maven

Figure 260. Newton's letter to Robert Hooke Slide presentation
Newton's letter to Robert Hooke

Figure 261. Application execution prerequisites Slide presentation

Figure 262. Why Maven project management? Slide presentation
  • Automated third-party class import and dependency management

  • Executing automated tests

  • Complete project lifecycle:

    compile, test, execute, package, deploy

  • Extensible plugin architecture


Figure 263. Example: Creating PDF using iText7 Slide presentation
Source: CreatePdf.java PDF output
import com.itextpdf.kernel.pdf.PdfDocument;
...
final PdfWriter writer = new PdfWriter("helloWorld.pdf");

final PdfDocument pdf = new PdfDocument(writer);

final Document document = 
   new Document(pdf, PageSize.A8.rotate());

document.add(new Paragraph("Hello World!").
     setFontColor(ColorConstants.MAGENTA).
     setFontSize(20));

document.close();
Example: Creating PDF using iText7

Figure 264. Maven iText library pom.xml definition Slide presentation
Maven iText library pom.xml definition
<project ...>
  ...
  <dependencies>
    <dependency>
      <groupId>com.itextpdf</groupId>
      <artifactId>itext-core</artifactId>
      <version>8.0.3</version>
      <type>pom</type>
    </dependency>
  </dependencies>
...

</project>

Figure 265. Itext transitive dependencies Slide presentation
mvn dependency:tree 
...
 --- dependency:3.6.1:tree (default-cli) @ hellopdf ---
 de.hdm_stuttgart.mi:hellopdf:jar:0.9
 \- com.itextpdf:itext-core:pom:8.0.2:compile
    +- com.itextpdf:barcodes:jar:8.0.2:compile
    |  \- org.slf4j:slf4j-api:jar:1.7.36:compile
    +- com.itextpdf:font-asian:jar:8.0.2:compile
    +- com.itextpdf:forms:jar:8.0.2:compile
    +- com.itextpdf:hyph:jar:8.0.2:compile
    +- com.itextpdf:io:jar:8.0.2:compile
    |  \- com.itextpdf:commons:jar:8.0.2:compile
    +- com.itextpdf:kernel:jar:8.0.2:compile ...

Figure 266. Class location in iText library Slide presentation
Class location in iText library

Figure 267. Class location in iText library Slide presentation
Class location in iText library

Figure 268. Maven repositories Slide presentation

exercise No. 108

Dealing with IBAN numbers

Q:

The java-iban framework provides methods for dealing with IBAN numbers. Create a new mi-maven-helloworld archetype based project. Add a <dependencies> section just before the existing <build> section and insert the latest artifact from https://mvnrepository.com/artifact/nl.garvelink.oss/iban.

Code and execute the following tasks:

  • Test both DE16 6009 0100 0175 0780 08 and DE16 6009 0100 0175 0780 09 for correct checksums.

  • Check whether PK12ASCM0000010110203819 belongs to the SWIFT registry and for being part of SEPA.

Note

See Java-IBAN for code examples.

A:

Code Result
public static void main( String[] args ) {

  System.out.println("DE16 6009 0100 0175 0780 08: " + Modulo97.verifyCheckDigits( "DE16 6009 0100 0175 0780 08" ));
  System.out.println("DE16 6009 0100 0175 0780 09: " + Modulo97.verifyCheckDigits( "DE16 6009 0100 0175 0780 09" ));
33
  final IBAN iban = IBAN.valueOf( "PK12ASCM0000010110203819");

  System.out.println("SWIFT: " + iban.isInSwiftRegistry());
  System.out.println("SEPA: " + iban.isSEPA());

  System.out.println("Length DE: " + CountryCodes.getLengthForCountryCode("DE"));
  System.out.println("Length FR: " + CountryCodes.getLengthForCountryCode("FR"));
  System.out.println("Length NL: " + CountryCodes.getLengthForCountryCode("NL"));
}
DE16 6009 0100 0175 0780 08: false
DE16 6009 0100 0175 0780 09: true
SWIFT: true
SEPA: false
Length DE: 22
Length FR: 27
Length NL: 18
Figure 269. Maven archetypes Slide presentation
  • Blueprints for projects.

  • Based on the pom.xml file:

    Project Object Model

  • Initial project creation.

  • CLI and IDE support.

  • Extensibility by archetype catalogs.

mvn archetype:generate
[INFO] Scanning for projects...
...
1: remote -> am.ik.archetype:elm-spring-boot-blank-archetype ...
2: remote -> am.ik.archetype:graalvm-blank-archetype ...
3: remote -> am.ik.archetype:graalvm-springmvc-blank-archetype ...
...
2083: remote -> org.apache.maven.archetypes:maven-archetype-quickstart...
...
3330: remote -> za.co.absa.hyperdrive:component-archetype_2.12 (-)
Choose a number or apply filter ...

Figure 270. Project «lottery» depending on «helper» Slide presentation
Project «lottery» depending on «helper»

Figure 271. Providing project «helper» Slide presentation
Helper.java pom.xml
package mi.calc.common;
public class Helper {
  static public long
    factorial(int n) {
    long result = 1;
    for (int i = 2;
        i <= n; i++) {
      result *= i;
    }
    return result;
  }
}
<project xmlns="http://maven.apache.org...>
     ...
 <groupId>mi.calc</groupId>
 <artifactId>common</artifactId>
 <version>1.0</version>
     ...
</project>

Figure 272. Install project «Common» Slide presentation
goik@goiki Helper> mvn install
[INFO] Scanning for projects...
[INFO] -------------------------------------------
[INFO] Building helper 0.9
...
[INFO] Installing .../Helper/target/helper-0.9.jar to
  /ma/goik/.m2/repository/mi/calc/common/1.0/common-1.0.jar

Figure 273. helper-0.9.jar archive content Slide presentation
goik@goiki tmp> unzip  ...hdm_stuttgart/de/mi/sd1/helper/0.9/helper-0.9.jar
Archive:  .../.m2/repository/.../sd1/helper/0.9/helper-0.9.jar
   creating: META-INF/
  inflating: META-INF/MANIFEST.MF
   creating: de/
   creating: de/hdm_stuttgart/
   creating: de/hdm_stuttgart/mi/
   creating: de/hdm_stuttgart/mi/sd1/
  inflating: de/hdm_stuttgart/mi/sd1/Helper.class
   creating: META-INF/maven/
   creating: META-INF/maven/de.hdm_stuttgart.mi.sd1/
   creating: META-INF/maven/de.hdm_stuttgart.mi.sd1/helper/
  inflating: META-INF/maven/de.hdm_stuttgart.mi.sd1/helper/pom.xml
  inflating: META-INF/maven/de.hdm_stuttgart.mi.sd1/helper/pom.properties

Figure 274. Consuming project «Lottery» Slide presentation
<project ...>
  ...
  <groupId>de.hdm_stuttgart.mi.sd1</groupId>
  <artifactId>lottery</artifactId>
  <version>0.9</version>

  <packaging>jar</packaging>
  <name>lottery</name>

  <dependencies>
    <dependency>
      <groupId>de.hdm_stuttgart.mi.sd1</groupId>
      <artifactId>helper</artifactId>
      <version>0.9</version>
    </dependency>
...
</project>

Figure 275. External libraries view Slide presentation
External libraries view

Figure 276. Using Helper.factorial(...) computing ( n k ) = n ! k ! ( n - k ) ! Slide presentation
static public long binomial(int n, int k) {
  return (Helper.factorial(n) / Helper.factorial(k)
                              / Helper.factorial(n - k));
}

public static void main(String[] args) {
  System.out.println("There are " + binomial(5, 2) +
      " ways to draw 2 out of 5 numbers");

  System.out.println("There are " + binomial(49, 6) +
      " ways to draw 6 out of 49 numbers");
}

Figure 277. Maven artifact dependency. Slide presentation

exercise No. 109

Cancelling fractions

When cancelling a fraction its greatest common divisor of denominator an nominator is being required. In the example of 12/18 this value is 6 allowing to cancel this fraction to 1/3.

Thus a project dealing with fractions may requires the import of your previous Finding the greatest common divisor of two integer values exercise. In this exercise you will solely work on your local ~/.m2/repositories drive:

  1. In your GCD exercise project create a local file system Maven export by executing mvn install . Alternatively you may hit Run --> Edit Configurations of your Idea IDE for defining a corresponding Maven runtime configuration by entering install in the »Command line« field.

  2. Defining Finding the greatest common divisor of two integer values as said dependency ❶ in your fraction related project:

    <project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation=
     "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    
      <modelVersion>4.0.0</modelVersion>
    
      <groupId>de.hdm-stuttgart.de.sd1</groupId>
      <artifactId>fraction</artifactId>
      <version>1.0</version>
      <packaging>jar</packaging>
    
      <name>fraction</name>
        ...
      <dependencies>
        <dependency> <groupId>de.hdm-stuttgart.de.sd1</groupId>
               <artifactId>gcd</artifactId>
               <version>1.0</version>
           </dependency>
        <dependency>
          <groupId>junit</groupId>
            ...
        </dependency>
      </dependencies>
    </project>

Q:

We have already implemented GCD computation in Finding the greatest common divisor of two integer values . The current exercise's idea is about implementing the operation of cancelling of fractions by using the method long getGcd(long a, long b). Change the following implementation items:

  • A fraction's constructor should cancel nominator and denominator if so required, see the introductory remark.

  • The Methods mult(...) and add(...) should cancel any resulting Fraction instance. Consider a defensive strategy to avoid unnecessary overflow errors.

Test your results.

A:

Modifying the constructor is straightforward: On creating a fraction we simply divide both numerator and denominator by the GCD value:

public Fraction(long numerator, long denominator) {
  final long gcd = Math.getGcd(numerator, denominator);

  setNumerator(numerator / gcd);
  setDenominator(denominator / gcd);
}

Its tempting to implement mult(...) in a simple fashion:

public Fraction mult2(Fraction f) {
  return new Fraction(numerator * f.numerator,
        denominator * f.denominator);
}

This is however too shortsighted. Consider the example 4 7 3 2 . Our simple implementation proposal would call new Fraction(12, 14) only to discover a GCD value of 4. Having larger argument values this might cause an unnecessary overflow. Moreover the GCD calculation will take longer than needed.

We may instead transform the term in question by exchanging the numerators like 3 7 4 2 to enable cancelling prior to multiplying. Now the call new Fraction(4,2) will construct the representation 2 1 and finishing the computation will yield the correct result 6 7 . We should thus implement:

public Fraction mult(Fraction f) {
  final Fraction f1 = new Fraction(f.numerator, denominator),
                 f2 = new Fraction(numerator, f.denominator);

  return new Fraction(f1.numerator * f2.numerator,
      f1.denominator * f2.denominator);
}

Similar reflections lead to the clue decomposing the denominators when implementing add(...). This is what you'd do as well if your task was adding two fractions by hand trying to avoid large numbers:

public Fraction add(Fraction f) {

  final long gcd = Math.getGcd(denominator, f.denominator);

  return new Fraction( numerator * (f.denominator / gcd) +
      (denominator / gcd) * f.numerator, (denominator / gcd) * f.denominator);
}

See complete implementation here. We may re-use out test:

public static void main(String[] args) {

  // Input
  final Fraction
    twoThird = new Fraction(2, 3),          // Construct a fraction object (2/3)
    threeSeven = new Fraction(3, 7);        // Construct a fraction object (3/7)

  // Computed results
  final Fraction
    sum = twoThird.add(threeSeven),         // (2/3) + (3/7)
    product = twoThird.mult(threeSeven);    // (2/3) * (3/7)

  System.out.println("(2/3) + (3/7) = (23/21) = " + sum.getValue());
  System.out.println("(2/3) * (3/7) = (2/7) = " + product.getValue());
}

exercise No. 110

Dealing with local Maven dependencies

Q:

This exercise is actually a preparation for ongoing exercises relying on importing local Maven artifacts.

Follow this section's description and create two projects A and B. Project B shall import some implementation from project A as being previously described. If you lack an idea you may just use the given Lottery project using the Helper project.