Skip to content

Commit e6d9c48

Browse files
author
Tomáš Kraus
committed
Data se imperative example with Oracle DB and UCP DataSource.
Signed-off-by: Tomáš Kraus <[email protected]>
1 parent 1863b56 commit e6d9c48

File tree

19 files changed

+860
-129
lines changed

19 files changed

+860
-129
lines changed

examples/data/mysql/README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,27 +53,27 @@ java -jar target/helidon-examples-data-mysql.jar
5353

5454
The application provides `http://localhost:8080/pokemon` endpoint.
5555

56-
**List all pokemons:**
56+
**List all pokémons:**
5757
```shell
5858
curl http://localhost:8080/pokemon/all
5959
```
6060

61-
**List all normal type pokemons:**
61+
**List all normal type pokémons:**
6262
```shell
6363
curl http://localhost:8080/pokemon/type/Normal
6464
```
6565

66-
**Retrieve a pokemon by name (`Meowth`):**
66+
**Retrieve a pokémon by name (`Meowth`):**
6767
```shell
6868
curl http://localhost:8080/pokemon/get/Meowth
6969
```
7070

71-
**Insert new pokemon:**
71+
**Insert new pokémon:**
7272
```shell
7373
curl -i -X POST -H 'Content-type: application/json' -d '{"name":"Charmander","type":"Fire"}' http://localhost:8080/pokemon
7474
```
7575

76-
**Delete existing pokemon by ID (`20`):**
76+
**Delete existing pokémon by ID (`20`):**
7777
```shell
7878
curl -i -X DELETE http://localhost:8080/pokemon/20
7979
```

examples/data/mysql/pom.xml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,7 @@
5959
</dependency>
6060
<dependency>
6161
<groupId>io.helidon.http.media</groupId>
62-
<artifactId>helidon-http-media-jsonb</artifactId>
63-
<scope>runtime</scope>
62+
<artifactId>helidon-http-media-jsonp</artifactId>
6463
</dependency>
6564
<dependency>
6665
<groupId>io.helidon.logging</groupId>

examples/data/mysql/src/main/java/io/helidon/examples/data/mysql/Main.java

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717

1818
import io.helidon.logging.common.LogConfig;
1919
import io.helidon.webserver.WebServer;
20-
import io.helidon.webserver.http.HttpRouting;
2120

2221
/**
2322
* The Main class serves as the entry point for the application.
@@ -35,30 +34,13 @@ private Main() {
3534
* @param args command-line arguments passed to the application
3635
*/
3736
public static void main(String... args) {
38-
39-
// load logging configuration
4037
LogConfig.configureRuntime();
41-
42-
// configure and start the HTTP server
4338
WebServer webServer = WebServer.builder()
4439
.port(8080)
45-
.routing(Main::routing)
40+
.routing(routing -> routing.register("/pokemon", new PokemonService()))
4641
.build();
4742
webServer.start();
4843
System.out.println("Server started on: http://localhost:" + webServer.port());
49-
50-
}
51-
52-
/**
53-
* Configures HTTP routing for the application.
54-
* Registers HTTP services with their respective endpoint prefixes.
55-
*
56-
* @param routing HTTP routing builder to configure routes for this service
57-
*/
58-
private static void routing(HttpRouting.Builder routing) {
59-
// register HTTP service with endpoint prefix
60-
routing.register("/pokemon", new PokemonService());
61-
6244
}
6345

6446
}

examples/data/mysql/src/main/java/io/helidon/examples/data/mysql/PokemonDto.java

Lines changed: 0 additions & 28 deletions
This file was deleted.

examples/data/mysql/src/main/java/io/helidon/examples/data/mysql/PokemonRepository.java

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,33 +15,43 @@
1515
*/
1616
package io.helidon.examples.data.mysql;
1717

18-
import java.util.List;
1918
import java.util.Optional;
19+
import java.util.stream.Stream;
2020

2121
import io.helidon.data.Data;
2222

23+
/**
24+
* {@link Pokemon} entity data repository interface.
25+
* <p>
26+
* {@code PokemonRepository} interface acts as a data access layer, encapsulating the logic for interacting
27+
* with the {@link Pokemon} entity data, and also provides basic CRUD (Create, Read, Update, Delete) operations
28+
* for the {@link Pokemon} entity.
29+
*
30+
* @see Data.CrudRepository
31+
* @see Pokemon
32+
*/
2333
@Data.Repository
2434
public interface PokemonRepository extends Data.CrudRepository<Pokemon, Integer> {
2535

2636
/**
27-
* Retrieves a list of {@link Pokemon} entities ordered by its {@code name}.
37+
* Retrieves a stream of {@link Pokemon} entities ordered by its {@code name}.
2838
* <p>
29-
* Query defined by method name: return list of {@link Pokemon} entities ordered by {@code name} property.
39+
* Query defined by method name: return stream of {@link Pokemon} entities ordered by {@code name} property.
3040
*
31-
* @return a list of {@link Pokemon} entities
41+
* @return a stream of {@link Pokemon} entities
3242
*/
33-
List<Pokemon> listOrderByName();
43+
Stream<Pokemon> streamOrderByName();
3444

3545
/**
36-
* Retrieves a list of {@link Pokemon} entities associated with a specific {@link Type} name.
46+
* Retrieves a stream of {@link Pokemon} entities associated with a specific {@link Type} name.
3747
* <p>
38-
* Query defined by method name: return unordered list of {@link Pokemon} entities with {@code breed.name}
39-
* property matching the {@code breedName} method argument.
48+
* Query defined by method name: return unordered stream of {@link Pokemon} entities with {@code type.name}
49+
* property matching the {@code typeName} method argument.
4050
*
41-
* @param breedName the name of the {@link Type}
42-
* @return a list of {@link Pokemon} entities with the specified breed name
51+
* @param typeName the name of the {@link Type}
52+
* @return a stream of {@link Pokemon} entities with the specified type name
4353
*/
44-
List<Pokemon> listByType_Name(String breedName);
54+
Stream<Pokemon> streamByType_Name(String typeName);
4555

4656
/**
4757
* Retrieves a {@link Pokemon} entity by its name.

examples/data/mysql/src/main/java/io/helidon/examples/data/mysql/PokemonService.java

Lines changed: 46 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
*/
1616
package io.helidon.examples.data.mysql;
1717

18+
import java.util.stream.Collector;
19+
1820
import io.helidon.http.BadRequestException;
1921
import io.helidon.service.registry.Services;
2022
import io.helidon.transaction.Tx;
@@ -24,90 +26,81 @@
2426
import io.helidon.webserver.http.ServerRequest;
2527
import io.helidon.webserver.http.ServerResponse;
2628

29+
import jakarta.json.Json;
30+
import jakarta.json.JsonArrayBuilder;
31+
import jakarta.json.JsonObject;
32+
2733
class PokemonService implements HttpService {
2834

29-
// Helidon Data repository interface providing Pokemon entity operations.
3035
private final PokemonRepository pokemonRepository = Services.get(PokemonRepository.class);
31-
// Helidon Data repository interface providing Pokemon entity operations.
3236
private final TypeRepository typeRepository = Services.get(TypeRepository.class);
3337

34-
// Pokemon endpoint routing rules
3538
@Override
3639
public void routing(HttpRules rules) {
3740
rules.get("/all", this::all)
3841
.get("/type/{name}", this::type)
3942
.get("/get/{name}", this::pokemon)
40-
.post("/", Handler.create(PokemonDto.class, this::insert))
43+
.post("/", Handler.create(JsonObject.class, this::insert))
4144
.delete("/{id}", this::delete);
4245
}
4346

44-
/**
45-
* Handles the {@code GET /all} request and returns a list of all {@link Pokemon} entities.
46-
*
47-
* @param request the server request
48-
* @param response the server response
49-
*/
5047
private void all(ServerRequest request, ServerResponse response) {
51-
response.send(pokemonRepository.listOrderByName());
48+
response.send(pokemonRepository.streamOrderByName()
49+
.map(pokemon -> Json.createObjectBuilder()
50+
.add("id", pokemon.getId())
51+
.add("name", pokemon.getName())
52+
.add("type", pokemon.getType().getName())
53+
.build())
54+
.collect(Collector.of(Json::createArrayBuilder,
55+
JsonArrayBuilder::add,
56+
JsonArrayBuilder::add,
57+
JsonArrayBuilder::build)));
5258
}
5359

54-
/**
55-
* Handles the {@code GET /type/{name}} request and returns a list of {@link Pokemon} entities
56-
* associated with a specific breed name.
57-
*
58-
* @param request the server request
59-
* @param response the server response
60-
*/
6160
private void type(ServerRequest request, ServerResponse response) {
6261
String name = request.path().pathParameters().get("name");
63-
response.send(pokemonRepository.listByType_Name(name));
64-
}
62+
response.send(pokemonRepository.streamByType_Name(name)
63+
.map(pokemon -> Json.createObjectBuilder()
64+
.add("id", pokemon.getId())
65+
.add("name", pokemon.getName())
66+
.add("type", pokemon.getType().getName())
67+
.build())
68+
.collect(Collector.of(Json::createArrayBuilder,
69+
JsonArrayBuilder::add,
70+
JsonArrayBuilder::add,
71+
JsonArrayBuilder::build))); }
6572

66-
/**
67-
* Handles the {@code GET /get/{name}} request and returns a {@link Pokemon} entity by its name.
68-
*
69-
* @param request the server request
70-
* @param response the server response
71-
*/
7273
private void pokemon(ServerRequest request, ServerResponse response) {
7374
String name = request.path().pathParameters().get("name");
74-
response.send(pokemonRepository.findByName(name));
75+
pokemonRepository.findByName(name)
76+
.ifPresentOrElse(
77+
pokemon -> response.send(Json.createObjectBuilder()
78+
.add("id", pokemon.getId())
79+
.add("name", pokemon.getName())
80+
.add("type", pokemon.getType().getName())
81+
.build()),
82+
() -> response.send(JsonObject.EMPTY_JSON_OBJECT));
7583
}
7684

77-
/**
78-
* Handles the {@code POST /} request and inserts a new {@link Pokemon} entity.
79-
* <p>
80-
* Pokémon entity content is supplied as JSON object and translated to {@link PokemonDto} class by HTTP
81-
* request processing layer.
82-
* Pokémon type record must already exist. Pokémon entity must not exist in the database.
83-
*
84-
* @param pokemonDto the pokémon to insert into the database
85-
* @param response the server response
86-
*/
87-
private void insert(PokemonDto pokemonDto, ServerResponse response) {
88-
// Pokemon data modification task is executed as single database transaction
89-
response.send(Tx.transaction(() -> {
90-
// Retrieve Type entity for provided name
91-
Type type = typeRepository.getByName(pokemonDto.type());
92-
// Prepare and insert new Pokemon entity into the database
93-
Pokemon pokemonEntity = new Pokemon(pokemonDto.name(), type);
85+
private void insert(JsonObject pokemonJson, ServerResponse response) {
86+
Pokemon pokemon = Tx.transaction(() -> {
87+
Type type = typeRepository.getByName(pokemonJson.getString("type"));
88+
Pokemon pokemonEntity = new Pokemon(pokemonJson.getString("name"), type);
9489
return pokemonRepository.insert(pokemonEntity);
95-
}));
90+
});
91+
response.send(Json.createObjectBuilder()
92+
.add("id", pokemon.getId())
93+
.add("name", pokemon.getName())
94+
.add("type", pokemon.getType().getName())
95+
.build());
9696
}
9797

98-
/**
99-
* Handles the {@code DELETE /{id}} request and deletes a {@link Pokemon} entity by its ID.
100-
*
101-
* @param request the server request
102-
* @param response the server response
103-
*/
10498
private void delete(ServerRequest request, ServerResponse response) {
10599
int id = request.path()
106100
.pathParameters()
107101
.first("id").map(Integer::parseInt)
108102
.orElseThrow(() -> new BadRequestException("No pokémon id"));
109-
// Rely on internal transaction handling for this simple data modification task
110-
response.send(new DmlResult(pokemonRepository.deleteById(id), "DELETE"));
103+
response.send("Deleted: " + pokemonRepository.deleteById(id) + " values");
111104
}
112105

113106
}

examples/data/mysql/src/main/java/io/helidon/examples/data/mysql/TypeRepository.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,33 @@
1+
/*
2+
* Copyright (c) 2025 Oracle and/or its affiliates.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
116
package io.helidon.examples.data.mysql;
217

318
import io.helidon.data.Data;
419

20+
/**
21+
* {@link Type} entity data repository interface.
22+
* <p>
23+
* {@code TypeRepository} interface acts as a data access layer, encapsulating the logic for interacting
24+
* with the {@link Type} entity data and provides user defined operations for the {@link Type} entity.
25+
*
26+
* @see Data.GenericRepository
27+
* @see Type
28+
*/
529
@Data.Repository
6-
public interface TypeRepository extends Data.GenericRepository <Type, Integer>{
30+
public interface TypeRepository extends Data.GenericRepository <Type, Integer> {
731

832
/**
933
* Retrieves a {@link Type} entity by its name.

0 commit comments

Comments
 (0)