Skip to content

Commit 2606361

Browse files
feature: integrate devin/1786033698-presentation-modernization
2 parents 1bc25da + f03dc37 commit 2606361

3 files changed

Lines changed: 159 additions & 140 deletions

File tree

README.md

Lines changed: 110 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1,134 +1,150 @@
11
# springboot-java8
2-
The project is made on spring boot. The project summarize the new features present in Java 8.
3-
It contain list of harcoded topics list. You can call the apis's with POSTMAN to add,delete,update Topic list
4-
In addition, it uses
5-
1) Java 8 NIO methods
6-
2) String operations
7-
3) Stream operations
8-
4) IntStream functions
9-
5) Functional interface
10-
6) Lambda functions
11-
7) Optional datatype
12-
8) Foreach loops
13-
9) Default and Static methods in interface
14-
10) Java 8 LocalDateTime API
15-
11) Pattern
16-
17-
18-
19-
## Getting Started
20-
1) Download or clone the project with link
21-
(https://github.com/RehmanMuradAli/springboot-java8/)
22-
23-
## Available API's
24-
25-
Greetings
26-
```
27-
GET /
28-
```
29-
Get all Topics in List
30-
```
31-
GET /topic
32-
```
33-
Get Topic of given ID
34-
```
35-
GET /topic/{id}
36-
```
372

38-
Add Topic in List
39-
```
40-
POST /topic
41-
```
42-
Update Topic of given ID
43-
```
44-
PUT /topic/{id}
45-
```
46-
Delete Topic of given ID
47-
```
48-
DELETE /topic/{id}
49-
```
3+
A small Spring Boot REST service whose purpose is to **demonstrate Java language features** — originally the Java 8
4+
feature set, which is still what the code shows off. The name stuck, but the project itself now builds and runs on
5+
**Java 21 with Spring Boot 3.5.16**.
506

51-
Get all Topics whose ID's length is greater than minLength
52-
```
53-
GET /topic/minimum/length/{minLength}
54-
```
7+
The domain is deliberately trivial: an in-memory, hardcoded list of `Topic` objects that you can create, read, update
8+
and delete over HTTP, plus a few endpoints that exist purely to print the result of stream / string / file operations.
559

56-
Get all Topics sorted by ID
57-
```
58-
GET /topic/sort
59-
```
10+
## Java 8 features demonstrated
6011

61-
String Operations on Topic List
62-
```
63-
GET /topic/string/operation
64-
```
12+
1. NIO.2 file APIs (`Files.list`, `Files.find`, `Files.walk`, `Files.newBufferedReader`)
13+
2. String operations (`String.join`, `String.chars`)
14+
3. Stream operations (`filter`, `map`, `sorted`, `Collectors.joining`)
15+
4. `IntStream` (`IntStream.range` for index lookups)
16+
5. Functional interfaces (`CustomPredicate<T>`)
17+
6. Lambda expressions
18+
7. `Optional` / `OptionalInt`
19+
8. `forEach` loops
20+
9. `default` and `static` methods on interfaces (`TimeClient`)
21+
10. The `java.time` API (`LocalDateTime`, `ZonedDateTime`, `ChronoUnit`)
22+
11. `Pattern` as a stream source and as a predicate (`splitAsStream`, `asPredicate`)
23+
12. try-with-resources over streams of paths
6524

66-
File Operations on Topic List
67-
```
68-
GET /topic/file/operation
69-
```
70-
Java 8 Date Time example
25+
## Java 21 idioms in use
26+
27+
The application was migrated from Spring Boot 2.0.2 / Java 8 to Spring Boot 3.5.16 / Java 21, and the presentation
28+
layer has been rewritten to use the modern language features that replace what the old code did by hand:
29+
30+
- **Text blocks** (Java 15) for the multi-part responses of `/datetime`, `/topic/string/operation` and
31+
`/topic/file/operation`, using `\` line-continuation escapes so the responses stay on a single line.
32+
- **`String.formatted(...)`** (Java 15) instead of `String.format(...)` and `+` concatenation.
33+
- Label templates are `private static final` constants rather than mutable instance fields.
34+
35+
## Requirements
36+
37+
- JDK 21 (the build sets `<java.version>21</java.version>`)
38+
- Maven is **not** required — use the bundled Maven Wrapper (`./mvnw`, Maven 3.9.9)
39+
- `curl`, HTTPie or Postman to call the API
40+
41+
## Getting started
42+
43+
```bash
44+
git clone https://github.com/COG-GTM/springboot-java8.git
45+
cd springboot-java8
46+
47+
# compile, run the test suite and package the jar
48+
./mvnw clean verify
49+
50+
# run the application (listens on http://localhost:8080)
51+
./mvnw spring-boot:run
7152
```
72-
GET /datetime
53+
54+
You can also run the packaged jar directly:
55+
56+
```bash
57+
java -jar target/gs-spring-boot-0.1.0.jar
7358
```
7459

60+
> The Gradle build has been removed; Maven is the only supported build.
61+
62+
Every push and pull request is built by GitHub Actions with `./mvnw -B clean verify` on JDK 21
63+
(see `.github/workflows/ci.yml`).
64+
65+
### Expected startup noise
7566

67+
- On startup the app creates an in-memory **H2** `customers` table with `JdbcTemplate` and logs a few rows — this is
68+
part of the demo, not an error.
69+
- It also tries to fetch a random quote from `gturnquist-quoters.cfapps.io`, a demo service that no longer exists.
70+
The resulting `WARN Could not fetch a quote from ...` is expected and must never fail startup.
7671

77-
### Prerequisites
72+
## API
7873

79-
1) Java sdk
80-
2) POSTMAN
74+
All endpoints are served from `http://localhost:8080`.
8175

82-
### Installing
76+
| Method | Path | Description |
77+
| --- | --- | --- |
78+
| `GET` | `/` | Greeting; accepts an optional `?name=` parameter (defaults to `World`) |
79+
| `GET` | `/topic` | All topics |
80+
| `GET` | `/topic/{id}` | A single topic by id |
81+
| `POST` | `/topic` | Add a topic (JSON body) |
82+
| `PUT` | `/topic/{id}` | Replace the topic with the given id |
83+
| `DELETE` | `/topic/{id}` | Delete the topic with the given id |
84+
| `GET` | `/topic/sort` | All topics sorted by id |
85+
| `GET` | `/topic/minimum/length/{minLength}` | Topics whose id is longer than `minLength` |
86+
| `GET` | `/topic/string/operation` | Plain-text dump of the string/stream/regex examples |
87+
| `GET` | `/topic/file/operation` | Plain-text dump of the NIO.2 file examples |
88+
| `GET` | `/datetime` | Plain-text dump of the `java.time` examples |
8389

90+
The topic list lives in memory, so `POST` / `PUT` / `DELETE` changes are lost when the application restarts.
8491

92+
### Examples
8593

94+
```bash
95+
$ curl 'http://localhost:8080/?name=Devin'
96+
{"id":1,"content":"Hello, Devin!"}
97+
98+
$ curl http://localhost:8080/topic
99+
[{"id":"spring","subjectName":"Spring Framework","subjectDescription":"Spring Framework Description"}, ...]
100+
101+
$ curl -X POST http://localhost:8080/topic \
102+
-H 'Content-Type: application/json' \
103+
-d '{"id":"kotlin","subjectName":"Kotlin","subjectDescription":"Kotlin Description"}'
86104
```
87-
1) Download or clone
88-
2) Import the project
89-
3) Run on location machine
90-
4) Open Postman, to call API's ( localhost:8080 )
105+
106+
The `/topic/file/operation` endpoint resolves paths relative to the working directory the application was started
107+
from, so its output depends on where you run it.
108+
109+
## Project layout
110+
111+
```
112+
src/main/java/hello
113+
├── Application.java # entry point + CommandLineRunner (H2 seeding, quote fetch)
114+
├── config/ # RestTemplate bean
115+
├── controller/ # GreetingController, TopicController, HelloController
116+
├── declaration/ # CustomPredicate, TimeClient (default/static interface methods)
117+
├── model/ # Topic, Greeting, Customer, Quote, Value, SimpleTimeClient
118+
└── service/ # TopicService — where most of the Java 8 examples live
91119
```
92120

121+
## Helpful links
93122

94-
## Helpful Links
95123
Spring:
96124

97125
https://spring.io/guides
98126

99-
Java 8:
127+
Java 8:
100128

101129
http://www.baeldung.com/java-8-functional-interfaces
102130

103-
http://winterbe.com/posts/2015/05/22/java8-concurrency-tutorial-atomic-concurrent-map-examples/
104-
105131
https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html
106132

107133
http://winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples/
108134

109-
http://www.oracle.com/technetwork/articles/java/ma14-java-se-8-streams-2177646.html
110-
111135
https://docs.oracle.com/javase/tutorial/essential/io/pathOps.html
112136

113-
https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html
114-
115-
http://www.baeldung.com/foreach-java
137+
Java 21:
116138

117-
http://winterbe.com/posts/2015/03/25/java8-examples-string-number-math-files/
139+
https://docs.oracle.com/en/java/javase/21/text-blocks/index.html
118140

119-
http://www.baeldung.com/java-8-comparator-comparing
141+
https://docs.spring.io/spring-boot/docs/current/reference/html/
120142

121-
http://www.baeldung.com/java-8-sort-lambda
143+
## Built with
122144

123-
https://dzone.com/articles/java-8-friday-goodies-new-new
124-
125-
126-
## Built With
127-
128-
* [Maven](https://maven.apache.org/) - Dependency Management
145+
* [Maven](https://maven.apache.org/) — build and dependency management
146+
* [Spring Boot](https://spring.io/projects/spring-boot) 3.5.16
129147

130148
## Authors
131149

132-
* **Rehman Murad Ali**
133-
134-
150+
* **Rehman Murad Ali** — original author

src/main/java/hello/controller/GreetingController.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,11 @@
99

1010
@RestController
1111
public class GreetingController {
12-
private static final String template = "Hello, %s!";
12+
private static final String TEMPLATE = "Hello, %s!";
1313
private final AtomicLong counter = new AtomicLong();
1414

1515
@RequestMapping("/")
1616
public Greeting greeting(@RequestParam(value="name", defaultValue="World") String name) {
17-
return new Greeting(counter.incrementAndGet(),
18-
String.format(template, name));
17+
return new Greeting(counter.incrementAndGet(), TEMPLATE.formatted(name));
1918
}
2019
}

src/main/java/hello/controller/HelloController.java

Lines changed: 47 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2,38 +2,37 @@
22

33
import hello.declaration.TimeClient;
44
import hello.model.SimpleTimeClient;
5-
import hello.model.Topic;
65
import hello.service.TopicService;
76
import org.springframework.beans.factory.annotation.Autowired;
8-
import org.springframework.web.bind.annotation.RestController;
97
import org.springframework.web.bind.annotation.RequestMapping;
8+
import org.springframework.web.bind.annotation.RestController;
109

1110
import java.time.LocalDate;
12-
import java.time.LocalDateTime;
13-
import java.time.LocalTime;
1411
import java.time.ZoneId;
15-
import java.time.chrono.ChronoPeriod;
1612
import java.time.temporal.ChronoUnit;
17-
import java.util.List;
18-
import java.util.regex.Pattern;
19-
import java.util.stream.Collector;
20-
import java.util.stream.Collectors;
2113

2214
@RestController
2315
public class HelloController {
2416

25-
26-
String joinTemplate = "Joining All String ID's with JOIN method: ";
27-
String makeDistinctAndSortCharactersTemplate = "-------------Get all ID characters, select distict and sort with ID= ";
28-
String splitAllIdWithColonSelectIDWithJavaKeywordThenSortThenJoinTemplate = "-------------Split All Id With Colon," +
29-
"Select ID With \"Java\" Keyword," +
30-
" Then Sort Then Join ";
31-
String findIdHavingCharacterTemplate = "-------------Return All ID having character \'g\' in it: ";
32-
String findAllFilesInPathAndSortTemplate = "---------Find all files in path and sort: ";
33-
String findParticularFileInPathAndSortTemplate = "----------Find File in present directory which strats with \"grad\",provided maximum depth=25 and sort : ";
34-
String findParticularFileInPathAndSortWithWalkFunctionTemplate = "----------Find File in present directory which strats with \"grad\",provided maximum depth=25 and sort : with walk function";
35-
String readFileWithStreamFunctionTemplate = "---------Read \"temp.txt\" file with stream functions, having \"print\" witin it: ";
36-
17+
private static final String JOIN_TEMPLATE = "Joining All String ID's with JOIN method: ";
18+
private static final String MAKE_DISTINCT_AND_SORT_CHARACTERS_TEMPLATE = "-------------Get all ID characters, select distict and sort with ID= ";
19+
private static final String SPLIT_ALL_ID_WITH_COLON_SELECT_ID_WITH_JAVA_KEYWORD_THEN_SORT_THEN_JOIN_TEMPLATE = """
20+
-------------Split All Id With Colon,\
21+
Select ID With "Java" Keyword,\
22+
Then Sort Then Join\s""";
23+
private static final String FIND_ID_HAVING_CHARACTER_TEMPLATE = "-------------Return All ID having character 'g' in it: ";
24+
private static final String FIND_ALL_FILES_IN_PATH_AND_SORT_TEMPLATE = "---------Find all files in path and sort: ";
25+
private static final String FIND_PARTICULAR_FILE_IN_PATH_AND_SORT_TEMPLATE = "----------Find File in present directory which strats with \"grad\",provided maximum depth=25 and sort : ";
26+
private static final String FIND_PARTICULAR_FILE_IN_PATH_AND_SORT_WITH_WALK_FUNCTION_TEMPLATE = "----------Find File in present directory which strats with \"grad\",provided maximum depth=25 and sort : with walk function";
27+
private static final String READ_FILE_WITH_STREAM_FUNCTION_TEMPLATE = "---------Read \"temp.txt\" file with stream functions, having \"print\" witin it: ";
28+
29+
/** Responses are single line, hence the trailing line-continuation escapes. */
30+
private static final String LABELLED_SECTIONS_FORMAT = """
31+
%s%s\
32+
%s%s\
33+
%s%s\
34+
%s%s\
35+
""";
3736

3837
@Autowired
3938
private TopicService topicService;
@@ -46,18 +45,23 @@ public class HelloController {
4645
@RequestMapping("/datetime")
4746
public String index() {
4847
TimeClient myTimeClient = new SimpleTimeClient();
49-
LocalDateTime localDateTime = LocalDateTime.now();
50-
return "Greetings from Spring Boot! ----------------------" +
51-
"Datetime now is " + String.valueOf(myTimeClient.toString()) + "----------------------" +
52-
"Datetime tomorrow will be " + String.valueOf(myTimeClient.getLocalDateTime().plusDays(1)) + "----------------------" +
53-
"Datetime of previous month was " + String.valueOf(myTimeClient.getLocalDateTime().minus(1, ChronoUnit.MONTHS)) + "----------------------" +
54-
"Is this a leap year ? " + String.valueOf(LocalDate.now().isLeapYear()) + "----------------------" +
55-
"Default system zone id " + String.valueOf(ZoneId.systemDefault()) + "-------------------" +
56-
"Time in California: " + myTimeClient.getZonedDateTime("Canada/Central").toString();
57-
48+
return """
49+
Greetings from Spring Boot! ----------------------\
50+
Datetime now is %s----------------------\
51+
Datetime tomorrow will be %s----------------------\
52+
Datetime of previous month was %s----------------------\
53+
Is this a leap year ? %s----------------------\
54+
Default system zone id %s-------------------\
55+
Time in California: %s\
56+
""".formatted(
57+
myTimeClient,
58+
myTimeClient.getLocalDateTime().plusDays(1),
59+
myTimeClient.getLocalDateTime().minus(1, ChronoUnit.MONTHS),
60+
LocalDate.now().isLeapYear(),
61+
ZoneId.systemDefault(),
62+
myTimeClient.getZonedDateTime("Canada/Central"));
5863
}
5964

60-
6165
/**
6266
* String Operations in Java 8
6367
*
@@ -72,16 +76,16 @@ public String showStringOperation() {
7276
.splitAllIdWithColonSelectIDWithJavaKeywordThenSortThenJoin(join);
7377
String findIdHavingCharacter = topicService.findIdHavingCharacter();
7478

75-
return joinTemplate + join
76-
+ makeDistinctAndSortCharactersTemplate + makeDistinctAndSortCharacters
77-
+ splitAllIdWithColonSelectIDWithJavaKeywordThenSortThenJoinTemplate + splitAllIdWithColonSelectIDWithJavaKeywordThenSortThenJoin
78-
+ findIdHavingCharacterTemplate + findIdHavingCharacter;
79-
79+
return LABELLED_SECTIONS_FORMAT.formatted(
80+
JOIN_TEMPLATE, join,
81+
MAKE_DISTINCT_AND_SORT_CHARACTERS_TEMPLATE, makeDistinctAndSortCharacters,
82+
SPLIT_ALL_ID_WITH_COLON_SELECT_ID_WITH_JAVA_KEYWORD_THEN_SORT_THEN_JOIN_TEMPLATE, splitAllIdWithColonSelectIDWithJavaKeywordThenSortThenJoin,
83+
FIND_ID_HAVING_CHARACTER_TEMPLATE, findIdHavingCharacter);
8084
}
8185

82-
8386
/**
8487
* File Operation in Java 8
88+
*
8589
* @return
8690
*/
8791
@RequestMapping("/topic/file/operation")
@@ -90,12 +94,12 @@ public String showFileOperation() {
9094
String findParticularFileInPathAndSort = topicService.findParticularFileInPathAndSort();
9195
String findParticularFileInPathAndSortWithWalkFunction = topicService.findParticularFileInPathAndSortWithWalkFunction();
9296
String readFileWithStreamFunction = topicService.readFileWithStreamFunction();
93-
return findAllFilesInPathAndSortTemplate + findAllFilesInPathAndSort
94-
+ findParticularFileInPathAndSortTemplate + findParticularFileInPathAndSort
95-
+ findParticularFileInPathAndSortWithWalkFunctionTemplate + findParticularFileInPathAndSortWithWalkFunction
96-
+ readFileWithStreamFunctionTemplate + readFileWithStreamFunction;
97-
}
98-
9997

98+
return LABELLED_SECTIONS_FORMAT.formatted(
99+
FIND_ALL_FILES_IN_PATH_AND_SORT_TEMPLATE, findAllFilesInPathAndSort,
100+
FIND_PARTICULAR_FILE_IN_PATH_AND_SORT_TEMPLATE, findParticularFileInPathAndSort,
101+
FIND_PARTICULAR_FILE_IN_PATH_AND_SORT_WITH_WALK_FUNCTION_TEMPLATE, findParticularFileInPathAndSortWithWalkFunction,
102+
READ_FILE_WITH_STREAM_FUNCTION_TEMPLATE, readFileWithStreamFunction);
103+
}
100104

101105
}

0 commit comments

Comments
 (0)