1. Reading

  • Horstmann Core Java, Ed 11, Vol I, Ch 5.7

2. Testing using reflection

2.1. Reflection and Testing

We use reflection quite a bit when correcting the tasks in performance assessments.

  • We cannot expect that a class that the candidate should write is present.

  • At the time of writing the tests it certainly is not available. We therefore have to instantiate the objects using reflection.

  • Sometimes the task states the requirement of only having a specific set of field types.

  • When you run the jacoco coverage plugin, jacoco itself adds so called synthetic members, which are not found in the source code of the business class, but are added by jacoco by way of instrumentation.

  • We want the candidates to stick to the naming conventions.

  • We want to check that a method or field has the required visibility, static-ness (static) or finality (final) or abstractness. This is defined as the set of modifiers of the member, and implemented as a simple set of bits, packed in a integer.

As an example verifying the visibility and other modifiers such as static and final may be subject of the correction work we need to do.

In the java .class file, the modifier of fields, methods and of types such as classes and interfaces are simply defined as a bit set packed into an int, and store with the byte code in the class file.

The following modifiers are defined:

Modifier

keyword

int value

Applies to

PUBLIC

public

1

C, F, M

PRIVATE

private

2

C, F, M

PROTECTED

protected

4

C, F, M

STATIC

static

8

C, F, M

FINAL

final

16

C, F, M

SYNCHRONIZED

synchronized

32

M

VOLATILE

volatile

64

F

TRANSIENT

transient

128

F

NATIVE

native

256

M

INTERFACE

interface

512

C

ABSTRACT

abstract

1024

C, M

STRICT

strict

2048

C, M

Applies to means Class, Field or Method.

Note that default or package private has no modifier bit of its own. If none of public, protected, or private is set, then that is when you get the default.

Below you see a selection of the helper methods we use to correct performance assessments.

Does the class' field name comply with the standard naming conventions?
/**
     * Check the field definition of a class, including naming conventions.
     *
     * @param targetClass to check
     * @param modifiers visibility, static, final
     * @param type of the field
     * @param fieldName of the field
     * @throws SecurityException when field is not accessible.
     */
    public static void checkFieldAndNaming( Class<?> targetClass,
                                            int modifiers, Class<?> type, String fieldName )
            throws SecurityException {
        if ( ( PUBLIC | STATIC | FINAL ) == modifiers ) {  (1)
            assertAllUpper( fieldName );
        } else {                                           (2)
            char firstChar = fieldName.charAt( 0 );
            assertEquals( "first char not lower case", "" + (char) Character.
                          toLowerCase(
                                  firstChar ), "" + (char) firstChar );
        }
        checkField( targetClass, modifiers, type, fieldName );
    }
1 Needs to be all UPPER CASE
2 Needs to start with a lower case character.
Check the modifiers on a field.
/**
 * Check the field definition of a class.
 *
 * This method tests if the required modifiers are set. Example: to check
 * private, but not require final, specify modifierMask == Modifier.PUBLIC |
 * Modifier.PRIVATE | Modifier.PROTECTED and as modsRequired
 *
 * @param targetClass to check
 * @param modifierMask visibility, static, final
 * @param modsRequired required modifiers
 * @param fieldType of the field
 * @param fieldName of the field
 * @throws SecurityException when field is not accessible
 */
public static void checkField( Class<?> targetClass,
                               int modifierMask,
                               int modsRequired,
                               Class<?> fieldType,
                               String fieldName )
        throws SecurityException {
    Field f = null;
    try {
        f = targetClass.getDeclaredField( fieldName );
        assertEquals( "field " + fieldName + " should be of type "
                + fieldType,
                      fieldType,
                      f.getType() );
        int fieldModifiers = f.getModifiers();
        if ( ( modifierMask & fieldModifiers ) != modsRequired ) {
            fail( "field '" + f.getName()
                    + "' should be declared '"
                    + Modifier.toString( modsRequired )
                    + "', you declared it '"
                    + Modifier.toString( fieldModifiers ) + '\'' );
        }
    } catch ( NoSuchFieldException ex ) {
        fail( "your class '" + targetClass
                + "' does not contain the required field '"
                + Modifier.toString( modifierMask )
                + " "
                + fieldType.getSimpleName()
                + " " + fieldName + "'" );
    }
}

2.2. Slides:

2.3. Additional pointers

3. Week 12 exercises

Class Genealogy

Class Genealogy

jbuttontree
Figure 1. inspiration for this task

Create a program that lists the class hierarchy of class names given on the command line.

The output should be a tree-like structure with Object at the top and the named class at the bottom and all intermediate super classes in between in proper order. For every level in the hierarchy, add two spaces for indentation.

To get a class object you can use Class.forName(String name) which, if the class is loadable by the JVM, is loaded.

As usual, start with writing the tests. The test class has two tests:

  1. One to show the genealogy of the Genealogy class itself.

  2. One to show the class hierarchy of javax.swing.JButton.

The picture only shows the direct lines of ancestry, not the interfaces. In this task you should show the implemented interfaces as well.

The elements that should be contained in the javax.swing.JButton are:

java.lang.Object

java.awt.Component

java.awt.image.ImageObserver

java.awt.MenuContainer

java.io.Serializable

java.awt.Container

javax.swing.JComponent

javax.swing.TransferHandler$HasGetTransferHandler

javax.swing.AbstractButton

java.awt.ItemSelectable

javax.swing.SwingConstants

javax.swing.JButton

javax.accessibility.Accessible

Example output for "javax.swing.JButton"
class hierarchy of [javax.swing.JButton]
 java.lang.Object
   java.awt.Component  implements java.awt.image.ImageObserver, java.awt.MenuContainer, java.io.Serializable
     java.awt.Container
       javax.swing.JComponent  implements javax.swing.TransferHandler$HasGetTransferHandler
         javax.swing.AbstractButton  implements java.awt.ItemSelectable, javax.swing.SwingConstants
           javax.swing.JButton  implements javax.accessibility.Accessible
Windows run script to run the genealogy program from the command line.
@echo off
rem @author David Greven - https://github.com/grevend
set jar=target/genealogy-1.0-SNAPSHOT.jar
if not exist %jar% cls & echo Maven... & call mvn package
echo.
java -jar %jar% %*
SQL table Generator

SQL table generator

Write an application that interprets the class definition of an entity class via reflection and spits out an SQL table definition.

The following java types and their sql counterparts should be supported. PostgreSQL types are used.

The name of the generated table should be the name of the entity class sans package name and in simple plural. Simple plural means append an 's' character to the name. Rationale: a table contains Students, plural, not student.

Java

SQL

java.lang.String

TEXT

java.lang.Character

CHAR(1)

java.lang.Integer

INTEGER

int

INTEGER

java.lang.Short

SMALLINT

short

SMALLINT

java.lang.Long

BIGINT

long

BIGINT

java.math.BigDecimal

DECIMAL

java.math.BigInteger

NUMERIC

java.lang.Float

REAL

float

REAL

java.lang.Double

DOUBLE PRECISION

double

DOUBLE PRECISION

java.time.LocalDate

DATE

java.time.LocalDateTime

TIMESTAMP

The generator should also support the following annotations on the fields of the entities.

@Id should generate a SERIAL or BIGSERIAL dependent on the field being a Integer or a Long and have the PRIMARY KEY attribute.
@NotNull should result in a NOT NULL constraint.
@Check should copy the value of the annotation as parameter to the CHECK constraint.
@Default should copy the value as the DEFAULT value. Quote the value where needed.

The resulting table definition should be acceptable by a postgreSQL database.

Example Module class.
@Data
@AllArgsConstructor
public class CourseModule {

    @ID
    private Integer moduleid;
    @NotNull
    String name;
    @NotNull
    @Default( value = "5" )
    @Check(credits > 0)
    Integer credits;
    // extra ctor to make the default value take effect.
    public CourseModule( Integer moduleid, String name ) {
        this( moduleid, name, 5 );
    }
}
Example Output.
CREATE TABLE coursemodules (
  moduleid SERIAL PRIMARY KEY,
  name TEXT NOT NULL,
  credits integer NOT NULL DEFAULT (5) CHECK (credits > 0)
);
Windows run script to run the sqlgenerator from the command line.
@echo off
rem @author David Greven - https://github.com/grevend
set jar=target/sqltablegenerator-1.0-SNAPSHOT.jar
if not exist %jar% cls & echo Maven... & call mvn package
echo.
java -jar %jar% %*
bash script to do the same as the above. Will work in git-bash too.
#!/bin/bash
jar=target/sqltablegenerator-1.0-SNAPSHOT.jar
if [ ! -e ${jar} ]; then mvn package; fi
java -jar ${jar} "$@"

3.1. Test run reports Week 12