Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
204 changes: 110 additions & 94 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,134 +1,150 @@
# springboot-java8
The project is made on spring boot. The project summarize the new features present in Java 8.
It contain list of harcoded topics list. You can call the apis's with POSTMAN to add,delete,update Topic list
In addition, it uses
1) Java 8 NIO methods
2) String operations
3) Stream operations
4) IntStream functions
5) Functional interface
6) Lambda functions
7) Optional datatype
8) Foreach loops
9) Default and Static methods in interface
10) Java 8 LocalDateTime API
11) Pattern



## Getting Started
1) Download or clone the project with link
(https://github.com/RehmanMuradAli/springboot-java8/)

## Available API's

Greetings
```
GET /
```
Get all Topics in List
```
GET /topic
```
Get Topic of given ID
```
GET /topic/{id}
```

Add Topic in List
```
POST /topic
```
Update Topic of given ID
```
PUT /topic/{id}
```
Delete Topic of given ID
```
DELETE /topic/{id}
```
A small Spring Boot REST service whose purpose is to **demonstrate Java language features** — originally the Java 8
feature set, which is still what the code shows off. The name stuck, but the project itself now builds and runs on
**Java 21 with Spring Boot 3.5.16**.

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

Get all Topics sorted by ID
```
GET /topic/sort
```
## Java 8 features demonstrated

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

File Operations on Topic List
```
GET /topic/file/operation
```
Java 8 Date Time example
## Java 21 idioms in use

The application was migrated from Spring Boot 2.0.2 / Java 8 to Spring Boot 3.5.16 / Java 21, and the presentation
layer has been rewritten to use the modern language features that replace what the old code did by hand:

- **Text blocks** (Java 15) for the multi-part responses of `/datetime`, `/topic/string/operation` and
`/topic/file/operation`, using `\` line-continuation escapes so the responses stay on a single line.
- **`String.formatted(...)`** (Java 15) instead of `String.format(...)` and `+` concatenation.
- Label templates are `private static final` constants rather than mutable instance fields.

## Requirements

- JDK 21 (the build sets `<java.version>21</java.version>`)
- Maven is **not** required — use the bundled Maven Wrapper (`./mvnw`, Maven 3.9.9)
- `curl`, HTTPie or Postman to call the API

## Getting started

```bash
git clone https://github.com/COG-GTM/springboot-java8.git
cd springboot-java8

# compile, run the test suite and package the jar
./mvnw clean verify

# run the application (listens on http://localhost:8080)
./mvnw spring-boot:run
```
GET /datetime

You can also run the packaged jar directly:

```bash
java -jar target/gs-spring-boot-0.1.0.jar
```

> The Gradle build has been removed; Maven is the only supported build.

Every push and pull request is built by GitHub Actions with `./mvnw -B clean verify` on JDK 21
(see `.github/workflows/ci.yml`).

### Expected startup noise

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

### Prerequisites
## API

1) Java sdk
2) POSTMAN
All endpoints are served from `http://localhost:8080`.

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

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

### Examples

```bash
$ curl 'http://localhost:8080/?name=Devin'
{"id":1,"content":"Hello, Devin!"}

$ curl http://localhost:8080/topic
[{"id":"spring","subjectName":"Spring Framework","subjectDescription":"Spring Framework Description"}, ...]

$ curl -X POST http://localhost:8080/topic \
-H 'Content-Type: application/json' \
-d '{"id":"kotlin","subjectName":"Kotlin","subjectDescription":"Kotlin Description"}'
```
1) Download or clone
2) Import the project
3) Run on location machine
4) Open Postman, to call API's ( localhost:8080 )

The `/topic/file/operation` endpoint resolves paths relative to the working directory the application was started
from, so its output depends on where you run it.

## Project layout

```
src/main/java/hello
├── Application.java # entry point + CommandLineRunner (H2 seeding, quote fetch)
├── config/ # RestTemplate bean
├── controller/ # GreetingController, TopicController, HelloController
├── declaration/ # CustomPredicate, TimeClient (default/static interface methods)
├── model/ # Topic, Greeting, Customer, Quote, Value, SimpleTimeClient
└── service/ # TopicService — where most of the Java 8 examples live
```

## Helpful links

## Helpful Links
Spring:

https://spring.io/guides

Java 8:
Java 8:

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

http://winterbe.com/posts/2015/05/22/java8-concurrency-tutorial-atomic-concurrent-map-examples/

https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html

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

http://www.oracle.com/technetwork/articles/java/ma14-java-se-8-streams-2177646.html

https://docs.oracle.com/javase/tutorial/essential/io/pathOps.html

https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html

http://www.baeldung.com/foreach-java
Java 21:

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

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

http://www.baeldung.com/java-8-sort-lambda
## Built with

https://dzone.com/articles/java-8-friday-goodies-new-new


## Built With

* [Maven](https://maven.apache.org/) - Dependency Management
* [Maven](https://maven.apache.org/) — build and dependency management
* [Spring Boot](https://spring.io/projects/spring-boot) 3.5.16

## Authors

* **Rehman Murad Ali**


* **Rehman Murad Ali** — original author
5 changes: 2 additions & 3 deletions src/main/java/hello/controller/GreetingController.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,11 @@

@RestController
public class GreetingController {
private static final String template = "Hello, %s!";
private static final String TEMPLATE = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();

@RequestMapping("/")
public Greeting greeting(@RequestParam(value="name", defaultValue="World") String name) {
return new Greeting(counter.incrementAndGet(),
String.format(template, name));
return new Greeting(counter.incrementAndGet(), TEMPLATE.formatted(name));
}
}
90 changes: 47 additions & 43 deletions src/main/java/hello/controller/HelloController.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,37 @@

import hello.declaration.TimeClient;
import hello.model.SimpleTimeClient;
import hello.model.Topic;
import hello.service.TopicService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.chrono.ChronoPeriod;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collector;
import java.util.stream.Collectors;

@RestController
public class HelloController {


String joinTemplate = "Joining All String ID's with JOIN method: ";
String makeDistinctAndSortCharactersTemplate = "-------------Get all ID characters, select distict and sort with ID= ";
String splitAllIdWithColonSelectIDWithJavaKeywordThenSortThenJoinTemplate = "-------------Split All Id With Colon," +
"Select ID With \"Java\" Keyword," +
" Then Sort Then Join ";
String findIdHavingCharacterTemplate = "-------------Return All ID having character \'g\' in it: ";
String findAllFilesInPathAndSortTemplate = "---------Find all files in path and sort: ";
String findParticularFileInPathAndSortTemplate = "----------Find File in present directory which strats with \"grad\",provided maximum depth=25 and sort : ";
String findParticularFileInPathAndSortWithWalkFunctionTemplate = "----------Find File in present directory which strats with \"grad\",provided maximum depth=25 and sort : with walk function";
String readFileWithStreamFunctionTemplate = "---------Read \"temp.txt\" file with stream functions, having \"print\" witin it: ";

private static final String JOIN_TEMPLATE = "Joining All String ID's with JOIN method: ";
private static final String MAKE_DISTINCT_AND_SORT_CHARACTERS_TEMPLATE = "-------------Get all ID characters, select distict and sort with ID= ";
private static final String SPLIT_ALL_ID_WITH_COLON_SELECT_ID_WITH_JAVA_KEYWORD_THEN_SORT_THEN_JOIN_TEMPLATE = """
-------------Split All Id With Colon,\
Select ID With "Java" Keyword,\
Then Sort Then Join\s""";
private static final String FIND_ID_HAVING_CHARACTER_TEMPLATE = "-------------Return All ID having character 'g' in it: ";
private static final String FIND_ALL_FILES_IN_PATH_AND_SORT_TEMPLATE = "---------Find all files in path and sort: ";
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 : ";
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";
private static final String READ_FILE_WITH_STREAM_FUNCTION_TEMPLATE = "---------Read \"temp.txt\" file with stream functions, having \"print\" witin it: ";

/** Responses are single line, hence the trailing line-continuation escapes. */
private static final String LABELLED_SECTIONS_FORMAT = """
%s%s\
%s%s\
%s%s\
%s%s\
""";

@Autowired
private TopicService topicService;
Expand All @@ -46,18 +45,23 @@ public class HelloController {
@RequestMapping("/datetime")
public String index() {
TimeClient myTimeClient = new SimpleTimeClient();
LocalDateTime localDateTime = LocalDateTime.now();
return "Greetings from Spring Boot! ----------------------" +
"Datetime now is " + String.valueOf(myTimeClient.toString()) + "----------------------" +
"Datetime tomorrow will be " + String.valueOf(myTimeClient.getLocalDateTime().plusDays(1)) + "----------------------" +
"Datetime of previous month was " + String.valueOf(myTimeClient.getLocalDateTime().minus(1, ChronoUnit.MONTHS)) + "----------------------" +
"Is this a leap year ? " + String.valueOf(LocalDate.now().isLeapYear()) + "----------------------" +
"Default system zone id " + String.valueOf(ZoneId.systemDefault()) + "-------------------" +
"Time in California: " + myTimeClient.getZonedDateTime("Canada/Central").toString();

return """
Greetings from Spring Boot! ----------------------\
Datetime now is %s----------------------\
Datetime tomorrow will be %s----------------------\
Datetime of previous month was %s----------------------\
Is this a leap year ? %s----------------------\
Default system zone id %s-------------------\
Time in California: %s\
""".formatted(
myTimeClient,
myTimeClient.getLocalDateTime().plusDays(1),
myTimeClient.getLocalDateTime().minus(1, ChronoUnit.MONTHS),
LocalDate.now().isLeapYear(),
ZoneId.systemDefault(),
myTimeClient.getZonedDateTime("Canada/Central"));
}


/**
* String Operations in Java 8
*
Expand All @@ -72,16 +76,16 @@ public String showStringOperation() {
.splitAllIdWithColonSelectIDWithJavaKeywordThenSortThenJoin(join);
String findIdHavingCharacter = topicService.findIdHavingCharacter();

return joinTemplate + join
+ makeDistinctAndSortCharactersTemplate + makeDistinctAndSortCharacters
+ splitAllIdWithColonSelectIDWithJavaKeywordThenSortThenJoinTemplate + splitAllIdWithColonSelectIDWithJavaKeywordThenSortThenJoin
+ findIdHavingCharacterTemplate + findIdHavingCharacter;

return LABELLED_SECTIONS_FORMAT.formatted(
JOIN_TEMPLATE, join,
MAKE_DISTINCT_AND_SORT_CHARACTERS_TEMPLATE, makeDistinctAndSortCharacters,
SPLIT_ALL_ID_WITH_COLON_SELECT_ID_WITH_JAVA_KEYWORD_THEN_SORT_THEN_JOIN_TEMPLATE, splitAllIdWithColonSelectIDWithJavaKeywordThenSortThenJoin,
FIND_ID_HAVING_CHARACTER_TEMPLATE, findIdHavingCharacter);
}


/**
* File Operation in Java 8
*
* @return
*/
@RequestMapping("/topic/file/operation")
Expand All @@ -90,12 +94,12 @@ public String showFileOperation() {
String findParticularFileInPathAndSort = topicService.findParticularFileInPathAndSort();
String findParticularFileInPathAndSortWithWalkFunction = topicService.findParticularFileInPathAndSortWithWalkFunction();
String readFileWithStreamFunction = topicService.readFileWithStreamFunction();
return findAllFilesInPathAndSortTemplate + findAllFilesInPathAndSort
+ findParticularFileInPathAndSortTemplate + findParticularFileInPathAndSort
+ findParticularFileInPathAndSortWithWalkFunctionTemplate + findParticularFileInPathAndSortWithWalkFunction
+ readFileWithStreamFunctionTemplate + readFileWithStreamFunction;
}


return LABELLED_SECTIONS_FORMAT.formatted(
FIND_ALL_FILES_IN_PATH_AND_SORT_TEMPLATE, findAllFilesInPathAndSort,
FIND_PARTICULAR_FILE_IN_PATH_AND_SORT_TEMPLATE, findParticularFileInPathAndSort,
FIND_PARTICULAR_FILE_IN_PATH_AND_SORT_WITH_WALK_FUNCTION_TEMPLATE, findParticularFileInPathAndSortWithWalkFunction,
READ_FILE_WITH_STREAM_FUNCTION_TEMPLATE, readFileWithStreamFunction);
}

}
Loading