Home » 2023 » Februar

Archiv für den Monat: Februar 2023

Sketchup – Merkpunkte (Anfänger)

Modell: Bezeichnet die Gesamtheit der Zeichung mit allen Teilen.
Objekt: Ein Teil des Modells.
Diese Unterscheidung ist wichtig, wenn man z.B. ein Objekt strecken möchte. Es ist dann wichtig das Objekt allein zur Bearbeitung ausgewählt zu haben (normalerweise über Rechtsklick > „Objekt bearbeiten“).

Betrachterperspektive ändern: Mittlere Maustaste drücken und Maus bewegen.
Modell verschieben: Mittlere und linke Maustaste gedrückt halten und Maus bewegen.
In Selektionsmodus wechseln: Space-Taste (oder Pfeil-Menu)

Zusammengehörende Objekte in einer Collection zusammenfassen – Mit Java Stream API

Angenommen wir haben eine Collection von Einkäufen (Joghurt, Bananen, Deodorant, Äpfel, Käse, …) und wir wollen diese zusammenfassen (z.B. Milchprodukte, Früchte, …) dann können wir das wie folgt machen:

Map<String, Purchase> condensedMap = purchases.stream()
    .collect(Collectors.groupingBy(Purchase::getCategory,
        Collectors.collectingAndThen(Collectors.reducing(
         (a,b) -> new Category(a.getCategory().name(), Math.sum(a.price(), b.price())), 
Optional::get))));

List<Category> condensedList = condensedMap.values();

Inspired by Java stream merge or reduce duplicate objects

Zyklische Dependencies Vermeiden, mit Dependeny Inversion

Problem

Wir haben ein Low Level (core) Module das von einem High Level (public Web) Module verwendet wird.
Nun gibt es einen neuen Fall, wo das High Module von vom Low Level Module aufgerufen werden muss. Dies ist eine umgekehrte Abhängigkeit!

edu.learn.highlevel.TuWasBean
interface HighLevelModuleTuWasServiceIntf{
  void tuWas(TuWasBean bean);
}

Das Problem ist, dass nun eine Zyklische Abhängigkeit (Cyclic Dependency) entsteht. Dies wird in unserem Fall zuallererst schmerzhaft, da High Level und Low Level Module im selben Build derselben Applikation gebaut werden. Dabei wird zuerst Low Level gebildet und dann High Level. Wenn man nun eine Anpassung am HighLevelModuleServiceIntf macht, dann muss man zuerst einen High Level Build laufen lassen, bevor man das Low Level auch adaptieren und bauen kann. (Sonst wäre ja das geänderte High Level Interface – auf das Low Level bereits aufbaut – noch gar nicht da.)

Lösung – Auflösung der Zyklischen Dependency

Die Lösung heisst „Dependency Inversion“. In unserem Fall heisst das, dass das Low Level Module so tut als sei der Service von ihm! Es definiert den Service selbst (und verlangt vom High Level Module, dass es selbst auf sein High Level Interface mappt).

Low Level Module formuliert also:

edu.learn.lowLevel.RepresentationOfTuWasBean
interface RepresentationOfTheHighLevelModuleTuWasServiceIntf{
   void tuWas(RepresentationOfTuWasBean bean);
}

Low Level codiert nun gegen sein eigenes Interface. Zur Runtime bezieht es vertrauensvoll eine Implementaion von RepresentationOfTheHighLevelModuleTuWasServiceIntf:

@Autowired
RepresentationOfTheHighLevelModuleTuWasServiceIntf service;

public void meinBusiness(){
   service.tuEtwas(RepresentationOfTuWasBean bean);
}

High Level muss dazu eine Implementierung des Low Level Interfaces zur Verfügung stellen. High Level Module mappt also selber das Low Level API zu seinem eigenen hin:

package edu.learn.highlevel.mapper;
import edu.learn.lowLevel.RepresentationOfTuWasBean
import edu.learn.highlevel.TuWasBean;

@Autowired
private OurBeanMapper beanMapper;

@Autowired
private HighLevelModuleTuWasServiceIntf highLevelService;

class TuWasServiceClientAdapter implements RepresentationOfTheHighLevelModuleTuWasServiceIntf {
   void tuWas(RepresentationOfTuWasBean lowLevelBean){
      TuWasBean highLevelBean = beanMapper.map(lowLevelBean);
      highLevelService.tuWas(highLevelBean);
   }
}

Durch diese Implementierung kann nun das High Level Module unabhängig vom Low Level Module Anpassungen an diesem API machen. Es ist einfach selbst verantwortlich das Low Level Interface weiterhin einzuhalten.
Das Low Level Module definiert den Zusammenarbeits-Vertrag. Das heisst: Auch hier ist nun High Level vom Low Level Abhängig.

Es ist nun auch möglich das Interface und dessen Nutzung (High und Low Level) anzupassen und gleichzeitig einem Build zuzuführen. Zuvor war das unmöglich, weil im ersten Schritt Low Level gebildet wurde, welches die angepassten Felder schon (zur Build-Zeit) im High Level Interface referenzierte. Nun kennt Low Level High level nicht mehr.

Zusätzlich Hilfreich …

… ist der Einsatz eines Bean-Mappers. Allein schon durch seinen Einsatz schlagen Feld-Anpassungen im Ziel-API nicht direkt auf Kompilierprobleme beim Consumer durch.

Java Runnable (EXE) erstellen / Runnable JAR erstellen

Wie erstelle ich ein Java-Programm, das ich mal einfach so einem Kollegen senden kann, das dieser dann auf seinen Computer kopiert und per Doppelklick ausführt.

(Java Web Start wäre wohl eine gute Wahl dafür gewesen, doch diese Technologie existiert seit Java 11 nicht mehr.)

Hat das Programm ein GUI (oder präziser: Braucht es keine Kommandozeile für die User-Interaktion) kann man ein „Doppelklickbares“ JAR aus dem Code erstellen.

Ausführbare JAR Datei erstellen

Eine doppelklickbare JAR Datei kann wie folgt erstellt werden.
Dies ist nicht zielführend mit Kommandozeilenprogrammen, die (ad hoc) Parameter verlangen. Nützlich ist diese Option hingegen für GUI Programme.

Main Klasse in Manifest referenzieren

Im MANIFEST.MF soll diese Zeile stehen:

Main-Class: ch.meine.MainKlasse
Dies kann erreicht werden indem dem pom.xml diese Plugin-Definition hinzugefüt wird:
<build>
        <plugins>

            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>ch.meine.MainKlasse</mainClass>
                        </manifest>
                    </archive>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
            </plugin>
        </plugins>
    </build>

Nun muss das Projekt gebildet werden:

mvn clean package assembly:single

Das entstande JAR-File kann mittels Doppelklick gestartet werden.
Wenn das Programm kein GUI ist wird es kaum sichtbar sein, weil es wohl anläuft aber potentiell sehr schnell wieder verschwindet.

Alternativ kann das JAR gestartet werden mit:

java -jar MeinProgramm.jar <parameters>

Auf Kommandozeile ausführen

Ein (wie oben beschrieben) ausführbar gemachtes JAR kann wie folgt ausgeführt werden:

java -jar MeinProgramm.jar <parameters>

Selbstverständlich kann dieser Aufruf in Shortcuts oder in (Power)Shell/Bat Scripts eingabaut werden (und eventuell so als ZIP dem Kunden geliefert werden).

Massen-Updates with JPA/Hibernate

update tableX set field1 = ‚value1‘ where field2 = ‚value2‘;

How is this implemented in JPA?

CriteriaBuilder builder = daoProvider.getEntityManager().getCriteriaBulder();
CriteriaUpdate<Entity> criteriaUpdate = builder.createCriteriaUpdate(Entity.class)
     .set(root.get("field"), value)
     .where(predicates);
int updated = entityManager.createQuery(criteriaUpdate).executeUpdate();

GIT Commits zusammen fassen

A: Git rebase interactive starten:

git rebase --interactive HEAD~N

Dabei bezeichnet N die anzahl der jüngsten Commits auf dem current Branch. Alternativ kann die Commit ID des ältesten einzubeziehenden Commits bezeichnet werden.

B: Mittels ’s‘ (sqisd) am Zeilenanfang, im augegangenen VI editor diejenigen Commits markieren, die miteinander verschmolzen werden sollen. Ich glaube einen der Commits muss man auf der Anweisung ‚pick‘ belassen, damit dort hinein gemixt wird.

C: Speichern (in VI: wq!)

D: Eine einzige zusammenfassende Commit-Meldung schreiben. Mit ‚#‘ auskommentierte Zeilen werden ignoriert. Speichern (wq!)

E: Fertig

Link: https://www.internalpointers.com/post/squash-commits-into-one-git