Home » Java Advanced

Archiv der Kategorie: Java Advanced

Java Design Patterns

Siehe auch: Java Design Principles 

Ein wunderbarer Kurs: Design Patterns in Java: The Big Picture by Esteban Herrera

Design Pattern Types

Unterscheidung 1: Structural | Behavioral | Creational
Unterscheidung 2: Class | Object centric

Wichtigste Design Patterns

Creational

Abstract Factory

Factory Method

Gemäss Herrera: Gleich wie ‚Abstract Factory‘ aber links und Creator und Produkt haben nur eine Hierarchie.
Gemäss Steinhauser: Eine getFactory() Methode erzeugt die Factory anhand eines Discriminators.

Builder

Singleton Pattern

Sinn: Es soll in der Laufzeitumgebung nur genau ein Objekt einer bestimmten Klasse geben.
Vorgehen: Einzigen parameterlosen Konstruktor der Klasse auf private setzen. Statisches Feld ‚instance‘, das die eine Instanz aufnimmt. Eine statische getInstance Methode wird benutzt um 1., falls ‚instance‘ noch NULL ist die Klasse zu instqanzieren und ‚instance‘ zu setzen und 2. die Instanz zu retournieren.

Behavioural

Strategy

State

Command

Observer Pattern

Template Method Pattern

Eine Basisklasse enthälte eine Methode (Bsp. processDocument()), die sowohl Verarbeitungsschritte enthält, die für alle Spezialfälle gleich sind (Bsp. backup(), validate()), aber auch solche, die je nach Fall differenziert werden sollen (Bsp. process()). Die zu differenzierenden Schritte werden in der Basisklasse als abstrakte Methoden ausgelagert und in spezifischen Subklassen konkretisiert.

Spezialfall:
Hooks: Wie Template Pattern, aber methoden sind nicht abstrakt und müssen deshalb nicht überschriben werden (default).

Visitor

Beschreibung fehlt noch!

Iterator

Beschreibung fehlt noch!

Structural

Facade Pattern

Zweck: Einen Orchestrator haben, der weiss wo was zu holen und wie zu verarbeiten ist. ==> Wie eine Main Methode.

Decorator Pattern

Um eine Pizza mit verschiedenen Zutaten zu dekorieren:

Das bedingt, dass die Decorators eine Instanz des Decoree halten und eine gemeinsame Methode (=>Interface) implementieren:

Proxy Pattern

(Object) Adapter Pattern

Zweck: Koppelung von Services ohne direkt von ihren Interfaces abhängig zu sein.

Composite

Bridge

Optional.ofNullable / Optional.map – Mehrstufig hierarchische NOT NULL Abfrage. Anstatt Abfrage auf != NULL

Schritt 1: Erstelle ein Optional auf dem Object auf das du null-wert-sicher zugreifen möchtest:

Optional isOptionallyNull = Optional.ofNullable(instOfClassANotShureIfNull);

Schritt 2: Greife auf Felder (und Child-Felder) zu Obwohl die Instanz selbst (oder ihre Children) ja null sein könnten: Map:

ClassC unterUnterObject = isOptionallyNull .map(ClassA::getSubObjB).map(ClassB::getSubC).orElseGet(ClassC::new)

Wie oben demonstriert können über mehrere Stufen aggregierte Sub-Objekte so abgefragt werden, obwohl man nicht weiss ob Vater- oder Zwischenobjekte NULL sein könnten.

Filtern von Stream-Objekten und Verarbeitung mit dem gefundenen Objekt (–> ifPresent)

if (v1 != null && issuerMap.containsKey(v1)) {
    phcCr.setIssuer(issuerMap.get(v1));
}

… kann dasselbe erreicht werden mit:

Optional.ofNullable(v1).filter(value -> issuerMap.containsKey(value))
.ifPresent(value -> phcCr.setIssuer(issuerMap.get(value)));

SSL debuggen

-Djavax.net.debug=ssl

JVM Heap / MethodArea / Stack

JVM Tuning: Heapsize, Stacksize and Garbage Collection Fundamental

Stack-Size:

What is the default stack size, can it grow, how does it work with garbage collection?

Default Stack Size

Mocks erzeugen für via Class spezifizierte Objekte

Probleme:

Problem 1: Dynamisches Mocking:

Eine Methode soll Mocks für verschiedene Service-Klassen definieren. In der Methode selbst kann nicht jede in ihr zu Mockende Klasse separat auscodiert werden.

D.h.:

Mockito.when(MeineKlasse.meinMethode())

ist nicht möglich.

Stattdessen wird der Methode ein Class -Objekt übergeben, die den zu mockenden Service definiert.

 

Problem 2:
Wenn ein bestimmter request vorliegt muss ein definierter Reply zurück gegeben werden.

MyObj2 mock = Mockito.mock(MyObj2.class);
Mockito.when(mock.returnOnObj(new Bohne1("X"))).thenReturn("desired return");

Problem 3 :
Definition einer Sequenz der durch den Mock zurückzugebender Return-Werte.

MyObj2 mock = Mockito.mock(MyObj2.class);
Mockito.when(mock.returnOnObj(Mockito.any())).thenReturn("1").thenReturn("2").thenReturn("3");

 

Beispiel, das alles obigen Probleme löst:

HPServiceMockFactory.

import org.mockito.stubbing.OngoingStubbing;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import static org.mockito.Matchers.anyObject;
import static org.mockito.Mockito.when;

public class HPServiceMockFactory<T> {

    public enum MockMatchingType {IN_SEQUENCE, BY_REQUEST_MATCH};

    public  <T> T prepareMock(T mock, Class bdType, String svcName, MockMatchingType mockMatchingType, Object[] parameters, Object[] desiredReturns){

        Method svc = null;
        for (Method method : bdType.getDeclaredMethods()) {
            // check if method with this name and number of arguments is declared
            if ((method.getParameterTypes().length == parameters.length) && (method.getName().equals(svcName))) {
                // check method parameters
                if (allinstanceof(parameters, method.getParameterTypes())) {
                    try {
                        Object[] paramsForInvocation = new Object[parameters.length];
                        for(int i = 0;  i < parameters.length; i++){
                            if(mockMatchingType.equals(MockMatchingType.IN_SEQUENCE)){
                                // When we want to invoke in sequence: First invocation gets desiredReturn[0], second gets desiredReturn[1], ...
                                // Then we should narrow only to anyObject parameters (or we could narrow the the suiting parameter classes)
                                paramsForInvocation[i] = anyObject();
                            }else{
                                // When we want the mock to return an answer which is defined by its request being equal as the one when the mock is called
                                // then we have to call the mock and pass the expected parameters BEFORE (farther below) define the return values (via the "thenReturn(..))
                                paramsForInvocation[i] = parameters[i];
                            }
                        }

                        svc = bdType.getDeclaredMethod(svcName, method.getParameterTypes());
                        svc.invoke(mock, paramsForInvocation);
                    } catch (NoSuchMethodException e) {
                        throw new IllegalStateException("Failed to initialize mock data, " + e.toString(), e);
                    } catch (InvocationTargetException e) {
                        throw new IllegalStateException("Failed to initialize mock data, " + e.toString(), e);
                    } catch (IllegalAccessException e) {
                        throw new IllegalStateException("Failed to initialize mock data, " + e.toString(), e);
                    }
                }
            }
        }

        if (svc == null) {
            throw new IllegalStateException("Service method could not be found");
        }

        OngoingStubbing<Object> ongoingStubbing = when(svc);
        for(Object desiredReturn : desiredReturns){
            ongoingStubbing = ongoingStubbing.thenReturn(desiredReturn);
        }


        return mock;

    }
    private boolean allinstanceof(Object obj[], Class<?> classes[]) {

        for (int i = 0; i < obj.length; i++) {
            Class<?> clazz = classes[i];
            Object o = obj[i];
            if (clazz.isPrimitive()) {
                if (clazz == boolean.class) {
                    if (!(o instanceof Boolean)) {
                        return false;
                    }
                } else if (clazz == int.class) {
                    if (!(o instanceof Integer)) {
                        return false;
                    }
                }
            } else {
                if (o != null && !clazz.isInstance(o)) {
                    return false;
                }
            }
        }

        return true;
    }
}

Aufrufende Klasse:

import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;

import java.util.Objects;

import static com.ubs.m0m.mock.HPServiceMockFactory.MockMatchingType.BY_REQUEST_MATCH;
import static com.ubs.m0m.mock.HPServiceMockFactory.MockMatchingType.IN_SEQUENCE;

/**
 * Demonstrates how Mockito.when(null) can be used to tell Mockito to
 * return a given value if  objects equals to given ones are passed to the mocked method
 */
public class HPServiceMockTest {
    @Test
    public void mustReturnMockAnswersAsDefinedInASequence(){
        HPService mockedObject = Mockito.mock(HPService.class);
        Object[] parameters = new Object[1];
        parameters[0] = new Bohne1("X");
        String[] desiredReturns = {"Response 1", "Response 2", "Response 3"};
        HPServiceMockFactory myServiceMockFactory = new HPServiceMockFactory<HPService>();
        myServiceMockFactory.prepareMock(mockedObject, HPService.class, "returnOnObj", IN_SEQUENCE,  parameters, desiredReturns);

        Assert.assertEquals(desiredReturns[0], mockedObject.returnOnObj(new Bohne1("ANY")));
        Assert.assertEquals(desiredReturns[1], mockedObject.returnOnObj(new Bohne1("ANY")));
        Assert.assertEquals(desiredReturns[2], mockedObject.returnOnObj(new Bohne1("ANY")));
    }

    @Test
    public void mustReturnMockAnswersThatMatchTheGivenRequest(){
        HPServiceMockFactory myServiceMockFactory = new HPServiceMockFactory<HPService>();
        HPService mockedObject = Mockito.mock(HPService.class);

        Object[] whenReqParams1 = new Object[1];
        whenReqParams1[0] = new Bohne1("Request that must match 1");
        String[] desiredReturns1 = {"Right Response 1"};
        myServiceMockFactory.prepareMock(mockedObject, HPService.class, "returnOnObj", BY_REQUEST_MATCH,  whenReqParams1, desiredReturns1);

        Object[] whenReqParams2 = new Object[1];
        whenReqParams2[0] = new Bohne1("Request that must match 2");
        String[] desiredReturns2 = {"Right Response 2"};
        myServiceMockFactory.prepareMock(mockedObject, HPService.class, "returnOnObj", BY_REQUEST_MATCH,  whenReqParams2, desiredReturns2);

        Assert.assertEquals(desiredReturns1[0], mockedObject.returnOnObj(new Bohne1("Request that must match 1")));
        Assert.assertEquals(desiredReturns2[0], mockedObject.returnOnObj(new Bohne1("Request that must match 2")));
        Assert.assertNull(mockedObject.returnOnObj(new Bohne1("ANY")));
    }

}
class HPService {
    public String returnOnObj(Bohne1 in){return  "not mocked";}
}
class Bohne1 {
    public String id;

    public Bohne1(String id) {
        this.id = id;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Bohne1)) return false;
        Bohne1 bohne1 = (Bohne1) o;
        return Objects.equals(id, bohne1.id);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}

Dynamische Mocking

Probleme:

Problem 1: Dynamisches Mocking:

Eine Methode soll Mocks für verschiedene Service-Klassen definieren. In der Methode selbst kann nicht jede in ihr zu Mockende Klasse separat auscodiert werden.

D.h.:

Mockito.when(MeineKlasse.meinMethode())

ist nicht möglich.

Stattdessen wird der Methode ein Class -Objekt übergeben, die den zu mockenden Service definiert.

 

Problem 2:
Wenn ein bestimmter request vorliegt muss ein definierter Reply zurück gegeben werden.

MyObj2 mock = Mockito.mock(MyObj2.class);
Mockito.when(mock.returnOnObj(new Bohne1("X"))).thenReturn("desired return");

Problem 3 :
Definition einer Sequenz der durch den Mock zurückzugebender Return-Werte.

MyObj2 mock = Mockito.mock(MyObj2.class);
Mockito.when(mock.returnOnObj(Mockito.any())).thenReturn("1").thenReturn("2").thenReturn("3");

 

Beispiel, das alles obigen Probleme löst:

HPServiceMockFactory.class

import org.mockito.stubbing.OngoingStubbing;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import static org.mockito.Matchers.anyObject;
import static org.mockito.Mockito.when;

public class HPServiceMockFactory<T> {

    public enum MockMatchingType {IN_SEQUENCE, BY_REQUEST_MATCH};

    public  <T> T prepareMock(T mock, Class bdType, String svcName, MockMatchingType mockMatchingType, Object[] parameters, Object[] desiredReturns){

        Method svc = null;
        for (Method method : bdType.getDeclaredMethods()) {
            // check if method with this name and number of arguments is declared
            if ((method.getParameterTypes().length == parameters.length) && (method.getName().equals(svcName))) {
                // check method parameters
                if (allinstanceof(parameters, method.getParameterTypes())) {
                    try {
                        Object[] paramsForInvocation = new Object[parameters.length];
                        for(int i = 0;  i < parameters.length; i++){
                            if(mockMatchingType.equals(MockMatchingType.IN_SEQUENCE)){
                                // When we want to invoke in sequence: First invocation gets desiredReturn[0], second gets desiredReturn[1], ...
                                // Then we should narrow only to anyObject parameters (or we could narrow the the suiting parameter classes)
                                paramsForInvocation[i] = anyObject();
                            }else{
                                // When we want the mock to return an answer which is defined by its request being equal as the one when the mock is called
                                // then we have to call the mock and pass the expected parameters BEFORE (farther below) define the return values (via the "thenReturn(..)) 
                                paramsForInvocation[i] = parameters[i];
                            }
                        }

                        svc = bdType.getDeclaredMethod(svcName, method.getParameterTypes());
                        svc.invoke(mock, paramsForInvocation);
                    } catch (NoSuchMethodException e) {
                        throw new IllegalStateException("Failed to initialize mock data, " + e.toString(), e);
                    } catch (InvocationTargetException e) {
                        throw new IllegalStateException("Failed to initialize mock data, " + e.toString(), e);
                    } catch (IllegalAccessException e) {
                        throw new IllegalStateException("Failed to initialize mock data, " + e.toString(), e);
                    }
                }
            }
        }

        if (svc == null) {
            throw new IllegalStateException("Service method could not be found");
        }

        OngoingStubbing<Object> ongoingStubbing = when(svc);
        for(Object desiredReturn : desiredReturns){
            ongoingStubbing = ongoingStubbing.thenReturn(desiredReturn);
        }


        return mock;

    }
    private boolean allinstanceof(Object obj[], Class<?> classes[]) {

        for (int i = 0; i < obj.length; i++) {
            Class<?> clazz = classes[i];
            Object o = obj[i];
            if (clazz.isPrimitive()) {
                if (clazz == boolean.class) {
                    if (!(o instanceof Boolean)) {
                        return false;
                    }
                } else if (clazz == int.class) {
                    if (!(o instanceof Integer)) {
                        return false;
                    }
                }
            } else {
                if (o != null && !clazz.isInstance(o)) {
                    return false;
                }
            }
        }

        return true;
    }
}

Test Klassen:

import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;

import java.util.Objects;

import static com.ubs.m0m.mock.HPServiceMockFactory.MockMatchingType.BY_REQUEST_MATCH;
import static com.ubs.m0m.mock.HPServiceMockFactory.MockMatchingType.IN_SEQUENCE;

/**
 * Demonstrates how Mockito.when(null) can be used to tell Mockito to
 * return a given value if  objects equals to given ones are passed to the mocked method
 */
public class HPServiceMockTest {
    @Test
    public void mustReturnMockAnswersAsDefinedInASequence(){
        HPService mockedObject = Mockito.mock(HPService.class);
        Object[] parameters = new Object[1];
        parameters[0] = new Bohne1("X");
        String[] desiredReturns = {"Response 1", "Response 2", "Response 3"};
        HPServiceMockFactory myServiceMockFactory = new HPServiceMockFactory<HPService>();
        myServiceMockFactory.prepareMock(mockedObject, HPService.class, "returnOnObj", IN_SEQUENCE,  parameters, desiredReturns);

        Assert.assertEquals(desiredReturns[0], mockedObject.returnOnObj(new Bohne1("ANY")));
        Assert.assertEquals(desiredReturns[1], mockedObject.returnOnObj(new Bohne1("ANY")));
        Assert.assertEquals(desiredReturns[2], mockedObject.returnOnObj(new Bohne1("ANY")));
    }

    @Test
    public void mustReturnMockAnswersThatMatchTheGivenRequest(){
        HPServiceMockFactory myServiceMockFactory = new HPServiceMockFactory<HPService>();
        HPService mockedObject = Mockito.mock(HPService.class);

        Object[] whenReqParams1 = new Object[1];
        whenReqParams1[0] = new Bohne1("Request that must match 1");
        String[] desiredReturns1 = {"Right Response 1"};
        myServiceMockFactory.prepareMock(mockedObject, HPService.class, "returnOnObj", BY_REQUEST_MATCH,  whenReqParams1, desiredReturns1);

        Object[] whenReqParams2 = new Object[1];
        whenReqParams2[0] = new Bohne1("Request that must match 2");
        String[] desiredReturns2 = {"Right Response 2"};
        myServiceMockFactory.prepareMock(mockedObject, HPService.class, "returnOnObj", BY_REQUEST_MATCH,  whenReqParams2, desiredReturns2);

        Assert.assertEquals(desiredReturns1[0], mockedObject.returnOnObj(new Bohne1("Request that must match 1")));
        Assert.assertEquals(desiredReturns2[0], mockedObject.returnOnObj(new Bohne1("Request that must match 2")));
        Assert.assertNull(mockedObject.returnOnObj(new Bohne1("ANY")));
    }

}
class HPService {
    public String returnOnObj(Bohne1 in){return  "not mocked";}
}
class Bohne1 {
    public String id;

    public Bohne1(String id) {
        this.id = id;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Bohne1)) return false;
        Bohne1 bohne1 = (Bohne1) o;
        return Objects.equals(id, bohne1.id);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}
... code ...

Mockito.when(null) – Return basierend auf equality zu gegebenem Input

Mockito.mock(null)

Weshalb sollte das sinn machen?

Mockito.when(null).thenReturn(meinObjekt)

bedeutet eigentlich: Liebes Mockito. Nimm den letzten Aufruf auf irgend einem Mock. Wenn irgendwann derselbe Aufruf mit denselben Parametern gemacht werden sollte, dann gib „meinObjekt“ zurück.

Dies wird unten demonstriert.

import org.mockito.Mockito;

import java.util.Objects;

/**
 * Demonstrates how Mockito.when(null) can be used to tell Mockito to 
 * return a given value if  objects equals to given ones are passed to the mocked method 
 */
public class HPTest {
    public static void main(String[] args) {
        MyObj mockedObject = Mockito.mock(MyObj.class);
        
        /* Tell Mockito, that if get1() is called, then return "super cool string 1.1"*/
        mockedObject.get1();
        Mockito.when(null).thenReturn("super cool string 1.1");
        mockedObject.get2();
        Mockito.when(null).thenReturn("super cool string 2");
        System.out.println(mockedObject.get1());
        System.out.println(mockedObject.get1());
        System.out.println(mockedObject.get2());
        System.out.println(mockedObject.toString());


        /* Tell Mockito, that if return1("1") is called, then return "Return 1" */
        mockedObject.return1("1");
        Mockito.when(null).thenReturn("Return 1");

        /* but if return1("2") is called, then return "Return 2" */
        mockedObject.return1("2");
        Mockito.when(null).thenReturn("Return 2");

        System.out.println(mockedObject.return1("1"));
        System.out.println(mockedObject.return1("2"));
        System.out.println(mockedObject.return1("2"));
        System.out.println(mockedObject.return1("1"));

        mockedObject.returnOnObj(new Bohne("A"));
        Mockito.when(null).thenReturn("On Obj A");

        mockedObject.returnOnObj(new Bohne("B"));
        Mockito.when(null).thenReturn("On Obj B");

        System.out.println(mockedObject.returnOnObj(new Bohne("A")));
        System.out.println(mockedObject.returnOnObj(new Bohne("B")));
        System.out.println(mockedObject.returnOnObj(new Bohne("B")));
        System.out.println(mockedObject.returnOnObj(new Bohne("A")));
    }

}
class MyObj {
    public String get1(){return "not mocked 1";}
    public String get2(){return "not mocked 2";}
    public String return1(String in){return  "not mocked";}
    public String returnOnObj(Bohne in){return  "not mocked";}
}
class Bohne {
    public String id;

    public Bohne(String id) {
        this.id = id;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Bohne)) return false;
        Bohne bohne = (Bohne) o;
        return Objects.equals(id, bohne.id);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}
/*
Output:
super cool string 1.1
super cool string 1.1
super cool string 2
Mock for MyObj, hashCode: 650023597
Return 1
Return 2
Return 2
Return 1
On Obj A
On Obj B
On Obj B
On Obj A

Process finished with exit code 0
 */

 

JavaScript in Java einlesen und ausführen

javax.script

Stream Reduce anwenden, um Auswertungen über Elemente zu machen

import static org.assertj.core.api.Assertions.assertThat;

public class LerneReduce {
    public static void main(String[] args) {
        List<String> bros = TestDataProvider.getBrothersInArms();

        assertThat(
            bros.stream().reduce((a, b) -> a + ", " + b).get()
        ).isEqualTo("Walther, Hans, Erich, Paul");

        IntStream oneTo3 = IntStream.iterate(1, i -> ++i).limit(3);
        assertThat(
             oneTo3.reduce((i1, i2) -> i1 + i2).getAsInt()
        ).isEqualTo(6);

    }
}

String-Joining mit Stream-API

import static org.assertj.core.api.Assertions.assertThat;

public class LerneJoining {
    public static void main(String[] args) {
        List<String> bros = TestDataProvider.getBrothersInArms();
        String brosString = bros.stream().collect(Collectors.joining(", ")); //Collectors.joining(...)
        assertThat(brosString).isEqualTo("Walther, Hans, Erich, Paul");
    }
}