Project dependencies and Maven

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

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

Figure 279. Providing project «helper» Slide presentation
Helper.java pom.xml
package
de.hdm_stuttgart.mi.sd1;
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...>
 <modelVersion>4.0.0</modelVersion>

 <groupId>de.hdm_stuttgart.mi.sd1</groupId>
 <artifactId>helper</artifactId>
 <version>0.9</version>
 <packaging>jar</packaging>
 <name>helper</name>
...
</project>

Figure 280. Install project «Helper» Slide presentation
goik@goiki Helper> mvn install
[INFO] Scanning for projects...
[INFO] -------------------------------------------
[INFO] Building helper 0.9
..
--------------------------------------------------
 T E S T S
--------------------------------------------------
Running de.hdm_stuttgart.de.mi.sd1.HelperTest
Tests run: 3, Failures: 0, Errors: 0, Skipped: 0,
...
[INFO] Installing .../Helper/target/helper-0.9.jar to
  /ma/goik/.m2/repository/de/hdm_stuttgart/mi/sd1/helper/0.9/helper-0.9.jar

Figure 281. 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 282. 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 283. External libraries view Slide presentation
External libraries view

Figure 284. 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 285. Maven artifact dependency. Slide presentation

exercise No. 113

Cancelling fractions

This exercise requires the import of the previous Maven based exercise Finding the greatest common divisor of two integer values . The import may be effected by:

  1. Creating a local Maven jar archive export by executing mvn install in project Finding the greatest common divisor of two integer values at the command line. Alternatively you may right click on your pom.xml file in Eclipse hitting Run as Maven build using install as goal.

  2. Defining Finding the greatest common divisor of two integer values as a dependency ❶ in your current 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>
          <scope>compile</scope>
        </dependency>
        <dependency>
          <groupId>junit</groupId>
            ...
        </dependency>
      </dependencies>
    </project>

Q:

We have implemented GCD computation in Finding the greatest common divisor of two integer values . The current exercises idea is to implement cancelling of fractions by using the method long getGcd(long a, long b). Change the following implementation items:

  • The constructor should cancel a fraction if required, see introductory remark.

  • The Methods mult(...) and add(...) should cancel any resulting Fraction instance. It might be worth to 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());
}
Figure 286. Maven repositories Slide presentation

exercise No. 114

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.