Archiv des Autors: admin
Bits, Kids & Karusselle: JavaLand4Kids 2023
Mein Beitrag „Bits, Kids und Karusselle“ über die JavaLand4Kids im Frühjahr im Phantasialand ist in der aktuellen Ausgabe 05/23 der „Java aktuell“ erschienen.
Viel Spaß beim Lesen und vielen Dank an alle, die mich bei der Erstellung dieses Beitrags unterstützt haben.
Digitaltag 2023
Dieses Jahr findet der bundesweite Digitaltag am 16. Juni 2023 statt. Auf über 2000 Aktionen können Menschen jeden Alters Digitalisierung erleben, Erfahrungen austauschen und auch mitgestalten.
Für junge Ingenieur:innen und Programmier:innen wird es an diesem Tag in der Bücherhalle Hamburg Volksdorf wieder meinen beliebten Workshop „LEGO Roboter bauen und programmieren“ geben. Weitere Informationen und Anmeldung wie gewohnt direkt über die Mitarbeiter:inner der Bücherhalle vor Ort.
Ein Weihnachtsgedicht
Das Christkind kommt zur Nacht
in stiller, heil’ger Pracht.
Es bringt uns Geschenke und Freud‘,
die Herzen leuchten hell und heut.
Es klopft an jedes Fensterlein,
die Augen leuchten fein und rein.
Es flüstert leise, sanft und mild:
„Frohe Weihnacht, liebes Kind!“
Es schenkt uns Glück und Frieden ein,
die Welt erscheint in heller Schein.
Es wünscht uns allen fröhliches Beisammensein,
in dieser heiligen, stillen Zeit.
Okay, ist nicht von mir, sondern von ChatGPT. Das Gedicht ist das Ergebnis meiner allerersten Anfrage bei der KI:
„Vom Christkind“ von Anna Richter ist mein Lieblingsgedicht. Kannst du ein ähnliches schreiben?
Faszinierende Technik. Für Weihnachtsgrußkarten ausreichend, oder? Mir fehlte aber der Wald:
Hmm, mir fehlt da was mit Wald im Gedicht.
Daraufhin wurde folgendes Gedicht generiert:
Im tiefen, dunklen Walde
ist es still und kalt.
Doch wenn das Christkind kommt,
leuchtet alles golden.
Die Bäume sind geschmückt,
die Luft ist voller Duft.
Es flüstert durch die Zweige:
„Frohe Weihnacht, liebes Volk!“
Der Schnee bedeckt den Boden,
die Sterne funkeln oben.
Es wird ein Fest gefeiert,
an diesem heiligen Ort.
Das Christkind bringt uns Freude,
in dieser stillen Nacht.
Es schenkt uns Liebe, Glück und Frieden,
in diesem wunderschönen Wald.
Okay, ist halt eine KI oder kein Dichter noch Denker…
From Hamburg to Hannover and back to Jorvik
Die letzten Wochen waren mit reichlich Workshops gespickt. Los ging es am 6. Oktober mit einem tollen Workshop auf dem Java Forum Nord. Vierzehn Schüler:innen der Montessori-Schule Hannover konnten dort gut drei Stunden lang kleine Roboter aus Legosteinen bauen und programmieren. Das kam so gut an, dass sich die Schule überlegt, das LEGO Education WeDo 2.0 Set auch anzuschaffen!
Kurze Luft schnappen und weiter ging es am 8. Oktober mit der Auftaktveranstaltung der Code Week in der Zentralbibliothek in Hamburg. Dort unterstützte ich zusammen mit Jens Blömer unseren Kids4IT-Mastermind Oliver Hook bei seinen beiden Sonic-Pi Workshops. Hier können Jugendliche Musik „programmieren“. Obwohl sich ältere Kinder eher weniger für MINT-Workshops begeistern lassen, waren beide Kurse bereits einige Tage zuvor ausgebucht. Der Weg über die Musik – viele der Teilnehmer:innen spielen selbst ein Musikinstrument – bietet hier einen alternativen Zugang zur Informatik.
Weiter ging es mit meinen eigenen Workshops im Rahmen der Code Week in der Bücherhalle Hamburg Volksdorf. Dort bot ich in diesem Jahr zwei Kurse an: Einen für ältere Kinder (Apitor Robot X) und den sehr beliebten, wieder lange im vorraus ausgebuchten Workshop für jüngere Kinder (siehe Hannover). Aber bei beiden Veranstaltungen verliessen Kinder mit strahlenden Gesichtern die jeweils drei-stündigen („Was, jetzt schon vorbei? Ich möchte noch weiter bauen…“) Workshops.
Das Finale war gestern auf dem PLAYfestifal im Jupiter. Auf dem Code Week Familiy Dinner habe ich Matthias Löwe kennengelernt; wir sprachen über unsere Tätigkeiten und Matthias berichtete von seinen aktuellen Vorbereitungen zum Festitival unter dem Motto „Take a Breath“. Ich erwähnte, das meine Tochter Star Stable Online spiele, ein Multiplayer-Pferdespiel, bei dem nicht die Quests im Spiel, sondern eigentlich die Interaktionen der Spieler untereinander im Vordergrund stehen. Zur meiner Überrauschung stimmte meine Tochter dem Vorschlag von Matthias und Heiko zu, auf der Speaker’s Corner etwas über das Spiel zu erzählen. Gut zwei Dutzend Zuschauer vor Ort und mehrere hundert online auf Twitch hörten sich den Vortrag an.
Tja, wird wohl Zeit, das Papa auch einen Vortrag auf einer Konferenz hält…
6. Hamburger MINT-Tag
Am 17. November findet der sechste Hamburger MINT-Tag statt. Klar, dass es an diesem Aktionstag auch einen Workshop in der Bücherhalle Hamburg Volksdorf zu diesem Thema geben wird.
Kids im Grundschulalter haben die Möglichkeit, mit dem LEGO Education WeDo 2.0 Set kleine Roboter aus Klemmbausteinen zu bauen und diese mit einer einfachen, graphischen Programmiersprache auf einem Tablet zu programmieren.
Der Kurs findet von 15 bis 18 Uhr statt. Anmeldungen wie üblich direkt in der Bücherhalle Volksdorf.
LEGO WeDo und Calliope Workshops auf dem Java Forum Nord
Das Java Forum Nord findet dieses Jahr am 6. Oktober 2022 im Hannover Congress Centrum statt. Neben tollen Vorträgen für Java-Enthusiasten (die Programmiersprache, nicht die Insel) wird es auch eine JFN4Kids geben.
Auf zwei Workshops können Kids aus ausgewählten Schulen einen Einblick in die IT bekommen. Für Grundschüler gibt es meinen klassischen LEGO WeDo 2.0 Workshop, für Gymnasiasten einen Calliope-Workshop.
Migration Kickstart-GraphlQL zu Spring Boot GraphQL
Seit Spring Boot 2.7.0 unterstützt das Framework GraphQL mit einer „nativen“ Integration, die auf GraphQL Java basiert. Wer zuvor die Kickstart-Variante genutzt hat, erfährt hier in knappen Zeilen, wie man seine Anwendung migriert.
Konfiguration
Der einfachste Teil. Die Konfigurationsparameter sind nun Teil des Spring-Namensraums. Die beiden wichtigsten Parameter am Besipiel:
Kickstart | Spring Boot |
graphql.servlet.mapping | spring.graphql.path |
graphiql.mapping | spring.graphql.graphiql.path |
QueryResolver
In Spring Boot läuft alles über @Controller
statt über Resolver und es kommen vermehrt Annotationen zum Einsatz. Hier ein einfaches Beispiel:
// Kickstart
@Component
public class Query implements GraphQLQueryResolver {
private final EntityManager entityManager;
public Marktpartner marktpartner(Long id) {
return entityManager.find(Marktpartner.class, id);
}
}
// Spring Boot
@Controller
public class Query {
private final EntityManager entityManager;
@QueryMapping
public Marktpartner marktpartner(@Argument Long id) {
return entityManager.find(Marktpartner.class, id);
}
}
Wenn im GraphQL-Schema weitere Attribute definiert waren, die nicht im zurückgegebenen Objekt enthalten waren, oder um Assoziationen aufzulösen, wurden weitere Resolver-Klassen geschrieben. In Spring Boot gibt es hierfür das @SchemaMapping
:
// Kickstart
@Component
public class MarktpartnerResolver implements GraphQLResolver<Marktpartner> {
public String getUri(Marktpartner marktpartner) {
return String.format(URL_VISITENKARTE, marktpartner.getId());
}
public Set<Marktfunktion> getMarktrollen(Marktpartner marktpartner, MarktrollenFilter filter) {
return repository.find...
}
}
@Controller
public class MarktpartnerResolver {
@SchemaMapping(typeName = "Marktpartner", field = "uri")
public String getUri(Marktpartner marktpartner) {
return String.format(URL_VISITENKARTE, marktpartner.getId());
}
@SchemaMapping(typeName = "Marktpartner", field = "marktrollen")
public Set<Marktfunktion> getMarktrollen(Marktpartner marktpartner, @Argument MarktrollenFilter filter) {
return repository.find...
}
}
Wichtig ist hierbei, das nur in @Controller
-annotierten Klassen nach @QueryMapping
oder @SchemaMapping
gesucht wird.
Relay-Unterstützung
In Spring Boot gibt es noch keine Unterstützung für Relay. Deshalb ist es notwendig, das Schema anzupassen. Dies führt nach meinem jetzigen Kenntnisstand leider auch dazu, dass Clients angepasst werden müssen, jedenfalls, wenn man erst einmal den einfachsten Weg geht.
// Kickstart
type Query {
marktpartner(id: ID!) : Marktpartner!
marktpartners(first: Int, after: String, last: Int, before: String, filter: MarktpartnerFilter) : MarktpartnerConnection @connection(for: "Marktpartner")
}
# Relay.js types:
# ---------------
interface Node {
id: ID
}
type PageInfo {
hasNextPage: Boolean!
hasPreviousPage: Boolean!
startCursor: String
endCursor: String
}
type Marktpartner implements Node {
id: ID!
name: String!
// ...
}
// Spring Boot
type Query {
marktpartner(id: ID!) : Marktpartner!
marktpartners(first: Int, after: String, last: Int, before: String, filter: MarktpartnerFilter) : Connection
}
# Relay.js types:
# ---------------
interface Node {
id: ID
}
type PageInfo {
hasNextPage: Boolean!
hasPreviousPage: Boolean!
startCursor: String
endCursor: String
}
type Connection {
edges: [Edge]
pageInfo: PageInfo
}
type Edge {
cursor: String!
node: Node!
}
type Marktpartner implements Node {
id: ID!
name: String!
// ...
}
Hinzu gekommen sind also die expliziten Typ-Definitionen für Connection und Edge.
Die obige Lösung führt jedoch dazu, dass Anfragen des Clients angepasst werden müssen:
// Kickstart
query Marktpartner($first: Int, $filter: MarktpartnerFilter, $marktrollen: MarktrollenFilter) {
marktpartners(first: $first, filter: $filter) {
edges {
cursor
node {
id
name
}
}
}
}
// Spring Boot
query Marktpartner($first: Int, $filter: MarktpartnerFilter, $marktrollen: MarktrollenFilter) {
marktpartners(first: $first, filter: $filter) {
edges {
cursor
node {
id
... on Marktpartner {
name
}
}
}
}
}
Außerdem wird noch eine TypeResolver
-Implementierung benötigt:
// Spring Boot
public class NodeTypeResolver implements TypeResolver {
@Override
public GraphQLObjectType getType(TypeResolutionEnvironment env) {
Object object = env.getObject();
if (object instanceof Marktpartner) {
return env.getSchema().getObjectType("Marktpartner");
}
throw new UnsupportedOperationException("NodeTypeResolver unvollständig für das Objekt " + object);
}
}
Testing
Am längsten hat die Umstellung der integrativen Tests gedauert, da ich dazu bisher nur wenige Beispiele gefunden hatte. Das wichtigste dabei: Es wird spring-webflux benötigt, auch wenn die Anwendung selbst gar nicht fluxig ist:
pom.xml (Spring Boot)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-graphql</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.graphql</groupId>
<artifactId>spring-graphql-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<scope>test</scope>
</dependency>
Für Tests gibt es in Spring Boot die Klasse GraphQlTester
und davon diverse Unterklassen für verschiedene Einsatzszenarien. Mein integrativer Test sieht nach der Umstellung wie folgt aus::
@Transactional
@SpringBootTest
class QueryIT {
private WebGraphQlTester tester;
@Autowired
private ObjectMapper objectMapper;
// ...
@Autowired
private WebApplicationContext context;
@BeforeEach
void before() {
WebTestClient webTestClient = MockMvcWebTestClient.bindToApplicationContext(context)
.configureClient()
.baseUrl("/api/graphql")
.defaultHeaders(headers -> headers.setBasicAuth("test", "test"))
.build();
tester = HttpGraphQlTester.create(webTestClient);
// Testdaten anlegen ...
}
@Test
void findetMarktpartnerUeberNameUndMarktrolle() {
MarktpartnerFilter filter = MarktpartnerFilter.builder().namensteil("acme").build();
MarktrollenFilter marktrollenFilter = MarktrollenFilter.builder()
.marktrollen(List.of(MarktfunktionRolle.LIEFERANT))
.build();
ObjectNode variables = objectMapper.createObjectNode();
variables.set("filter", objectMapper.convertValue(filter, ObjectNode.class));
variables.set("marktrollen", objectMapper.convertValue(marktrollenFilter, ObjectNode.class));
variables.put("first", 10L);
tester.documentName("marktpartners")
.variable("filter", variables.get("filter"))
.variable("marktrollen", variables.get("marktrollen"))
.variable("first", variables.get("first"))
.execute()
.path("marktpartners.edges").entityList(EdgeDummy.class).hasSize(1)
.path("marktpartners.edges[0].node.name").entity(String.class).isEqualTo("ACME Energie GmbH")
;
}
}
Zunächst wird also ein WebTestClient
erzeugt und konfiguriert und anschließend ein HttpGraphQlTester
. Dieser wird dann im eigentlich Test verwendet, um einen GraphQL-Aufruf durchzuführen. Wird wie oben eine documentName("marktpartners")
angegeben, dann sucht das System die Datei resources/graphql-test/marktpartners.graphql
. Alternativ kann mit der Methode document
die GraphQL-Anfrage als String übergeben werden.
Mit execute
wird die Anfrage gesendet und anschließend das Ergebnis geprüft. Hier kommen die path
-Aufrufe zum Einsatz und Standardvergleichsmethoden wie hasSize
oder isEqualTo
.
Stolperfallen und andere Anomalitäten
Kleine Sammlung von Inkompatibilitäten zum Verhalten von Kickstart-GraphQL:
- Verwende
List
stattSet
(beiSet<Enumtyp>
gab es Exeptions, dass auf ein Property nicht zugegriffen werden kann) - Bean-Standard für Rückgabe-DTOs einhalten, also Methoden nicht
edges()
benennen sonderngetEdges()
Walddörfer Gymnasium setzt Zeichen gegen den Krieg in der Ukraine
Die Schülerinnen und Schüler des Walddörfer Gymnasiums, das auch unsere Tochter besucht, haben am Dienstag ein unübersehbares Zeichen gegen den Krieg in der Ukraine gesetzt:
Auch das ZDF berichtete auf Twitter über diese Aktion.
Workshops 2022
Auch 2022 wird es wieder meine beliebten Kurse zum Bauen und Programmieren kleiner Roboter mit Klemmbausteinen geben. Nicht nur mit dem bekannten LEGO Education WeDo 2.0, sondern dieses Jahr auch erstmals mit dem Apitor Robot X, ein Robotic-Set von OpenBrickSource mit alternativen (aber kompatiblen) Klemmbausteinen (für die Insider: Die Steine sind von Gobricks).
Der Apitor wendet sich an etwas ältere Kinder. Mit der zum Set zugehörigen App kommen Bauanleitungen für zwölf verschiedene Konstruktionen, vom Roboter, über Rennwagen und Dinosaurier zum E-Piano, Geige und noch weiteren Modellen.
Und wie jedes Jahr gibt es auch 2022 wieder eine Code Week (vom 8. bis 23. Oktober). Freut euch auch auf den Digitaltag am 24. Juni und den Hamburger MINT-Tag am 17. November.
Termine „LEGO-Roboter bauen und programmieren“
Alle Veranstaltungen finden in der Bücherhalle Hamburg-Volksdorf statt. Anmeldungen vor Ort.
Sonnabend, 16. April 2022, 10 – 13 Uhr- Mittwoch, 25. Mai 2022, 15 – 18 Uhr
- Freitag, 24. Juni 2022, 15 – 18 Uhr (Digitaltag)
- Sonnabend, 6. August 2022, 10 – 13 Uhr
- Oktober, Code Week
- Sonnabend, 10. Dezember 2022, 10 – 13 Uhr
Termine „Apitor Robot X: Klemmbausteinroboter programmieren“
Alle Veranstaltungen finden in der Bücherhalle Hamburg-Volksdorf statt. Anmeldungen vor Ort.
- Sonnabend, 28. Mai 2022, 10 – 13 Uhr
- Sonnabend, 9. Juli 2022, 10 – 13 Uhr
- Oktober, Code Week