This repository contains projects that are an outcome of my work placement
(as a part of my first-cycle studies) in ADB POLSKA SP. Z O.O. (ZIELONA GORA OFFICE)
that took place in July 2021. In the process of work placement I have been introduced to foundations of
Spring framework
. The culmination of work was to implement an example of simple REST API
.
Note that this is not original repository I was working on during work placement. Projects included here has been improved in terms of code quality after self-reviewing the code. However, the general idea of the projects remained the same. Dependencies were updated since the creation of each project, but only up to a certain point.
- EX1-BEANS
- Project Details
- Dependencies
- EX2-BEANS
- Project Details
- Dependencies
- EX3-SCHEDULING
- Project Details
- Dependencies
- EX4-STREAM-API-JUNIT-TESTS
- Project Details
- Class Hierarchy Tree
- Dependencies
- EX5-EXPERIMENTAL-GET-MAPPING
- Project Details
- API Reference
- RegEx Details
- About Further Formatting
name
- API Response Examples
- Dependencies
- EX6-H2-STUDENTS
- Project Details
- Screenshots
- Dependencies
- EX7-RESTAPI-H2-BUSSES
- Project Details
- API Reference
- RegEx Details
- API Response Examples
- Screenshots
- Dependencies
This project was focused on presentation of application of inversion of control (IoC)
using simple
Spring Beans that were managed by a Spring Container implemented as a
AnnotationConfigApplicationContext class. The application is also writing in and reading out specific information
to/from a created properties file at app running. The file looks as follows:
#Wed Jul 07 09:31:52 CEST 2021
date=2021-07-07
java-version=11.0.11
program-version=1.0
where date
is computed locally by current date - java.time.LocalDate().now
and java-version
is an sdk
version.
- Project Details
- Dependencies
Java 11 (LTS)
Spring 5
Maven
- Properties file: custom.properties
ArtifactId | Version |
---|---|
spring-context | 5.3.23 |
This project was focused on using dependency injection
in action by defining a Spring Bean
with a priority using @Primary
annotation and also by specifying beans' name attribute.
The injection takes place in a method parameter of the other bean. The project also presented an idea of two
cooling systems implementations: Fridge class
and Air Conditioning class
.
- Project Details
- Dependencies
Java 11 (LTS)
Spring Boot 2
Maven
ArtifactId | Version |
---|---|
spring-boot-starter | 2.7.5 |
spring-boot-autoconfigure | 2.7.5 |
This project has shown how to schedule a task with Spring using @Scheduled
annotation.
The task was focused on sending GET
requests to chosen Web API
and process each response.
- (Expected) Processed response:
RANDOM_FACT_HERE
Random facts are printed on console every 8s.
- Project Details
- Dependencies
Java 11 (LTS)
Spring Boot 2
Maven
- API Docs
ArtifactId | Version |
---|---|
spring-boot-starter | 2.7.5 |
spring-boot-autoconfigure | 2.7.5 |
This project was focused on both usage of stream API
and unit testing with
JUnit Jupiter
framework. The purpose of the project has been satisfied based on an abstract
implementation of dogs and cats.
- Project Details
- Class Hierarchy Tree
- Dependencies
Java 11 (LTS)
Maven
- Unit tests
- Object (java.lang)
- Enum (java.lang)
- Hairiness
- CatHunterSense
- DogCommand
- Animal
- Cat
- Dog
- AnimalUtils
- AbstractCollection (java.util)
- AbstractList (java.util)
- ArrayList (java.util)
- CustomizedArrayList
- ArrayList (java.util)
- AbstractList (java.util)
- Enum (java.lang)
ArtifactId | Version |
---|---|
lombok | 1.18.24 |
JUnit Jupiter API | 5.9.0 |
JUnit Jupiter Params | 5.9.0 |
This project started as an experiment. It was focused on creating first basic Web API
.
Mapping was only provided for GET
method. The concept of the project can be described as:
- User sends a request with a parameter key
name
and (optionally) defined value. - API sends a response determined by the provided value of the key.
- If the value of the key is
undefined
, equals tostranger
or it DOES NOT MATCH specifiedregex
,API
returns general response (or error response in some cases). - Personalized responses'
ids
are incremented by 1 and all general responses'ids
are always 0. - Incrementation is stopped being followed once application has been shut down.
- Values of the key are being formatted before the
API
returns a response. Read further for details.
The general idea is that user can introduce themselves in a request and then API returns a welcome message as a response.
The application produces data in json
format.
- Project Details
- API Reference
- RegEx Details
- About Further Formatting
name
- API Response Examples
- Dependencies
Java 11 (LTS)
Spring Boot 2
Maven
- Runs
Tomcat
on default configuration (port 8080)
GET /meeting
GET /meeting?name=String
Key | Value | Description |
---|---|---|
name |
String |
Optional. Your name. stranger by default. |
RegEx
to match for the key name
^(?!.*[\r\n])[\da-zA-Z ]+$
To match this regex
it is necessary that:
- Provided String IS NOT BLANK.
- Provided String contains only latin letter(s) in lower or UPPER case or/and number(s) between 0 and 9 or/and space character(s).
- Provided String has a single line.
- Let's say we provide value:
%20L%20u%20%20c%20%20%20as%20%20
where%20
is encoding for a space character. - Value is being validated. In this case, validation is successful.
- Now it's time for formatting. To simplify how it works, it can be said that:
- We split validated String to multiple strings by each occurred space character.
- We take each String that DOES NOT contain a space character, and we append it to the output.
- After each, EXCEPT LAST appended String, we append a singular space character additionally.
- Formatted output looks like this:
L u c as
.
In short, it can be said that every formatted value starts and ends with a latin letter or with a number, and between any pair (if exists) of the space characters, there is at least one latin letter or a number.
General:
{
"id": 0,
"message": "Hello stranger. It's nice to meet you."
}
Examples:
GET /meeting?name=L%20u%20c%20as
{
"id": 1,
"message": "Hello L u c as. It's nice to meet you."
}
GET /meeting?name=0Lucas3
{
"id": 2,
"message": "Hello 0Lucas3. It's nice to meet you."
}
GET /meeting?name=10
{
"id": 3,
"message": "Hello 10. It's nice to meet you."
}
Note that it is still possible to force the API to return an error response.
ArtifactId | Version |
---|---|
lombok | 1.18.24 |
spring-boot-starter-web | 2.7.5 |
spring-boot-autoconfigure | 2.7.5 |
This project was focused on defining Entity class
and Spring Data JPA
repositories implementation.
It was built additionally with Spring Component class, Spring Configuration class and
Spring Service class. Configuration class implements CommandLineRunner interface
and
its method for providing execution of business logic defined in the service class, while the component class
is responsible for value injection
from properties file using @Value
annotation.
The value is used to define a number of students to create and add to the repository. Each student is created randomly
using data from Datafaker
library. For the presentation needs of findBySurname(String)
method,
it has been guaranteed that for n-students, there are exactly ⌊0,3*n⌋ students
named Lopez.
Each student id
is autogenerated during entity creation. Created entities can be managed by
H2 DBMS
. Properties file for this project looks as follows:
instances.number=15
server.port=8080
spring.jpa.open-in-view=false
spring.h2.console.enabled=true
spring.h2.console.path=/h2
spring.datasource.url=jdbc:h2:mem:students
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
- Project Details
- Screenshots
- Dependencies
Java 11 (LTS)
Spring Boot 2
Maven
- Runs
Tomcat
on port:8080
- Properties file: application.properties
ArtifactId | Version |
---|---|
datafaker | 1.7.0 |
lombok | 1.18.24 |
spring-context | 5.3.23 |
spring-boot | 2.7.5 |
spring-boot-starter-web | 2.7.5 |
spring-boot-starter-data-jpa | 2.7.5 |
h2 | 2.1.214 |
This project was focused on simple REST API
implementation. The project is built from the following components:
- Spring Configuration class
- Spring Rest Controller class
- Spring Service class
- Spring Data JPA repository
- Spring Rest Controller Adviser class
- Exception classes
- Response Body class
- Model class
- Entity class
- Utility classes
Utility classes delivers following functionalities:
- Bus conversion. Mapping entities to model representation (and vice versa).
- Data generator for busses.
- Validation for
String
values. - Shuffling data to ensure pseudo-random results.
Handled exceptions using @ExceptionsHandler
annotation:
- BusNotFound - thrown, if it could not find a bus with given
id
. - BusAlreadyExists - thrown, if it could not add a bus with given
id
(id already taken) - And others
The application consumes and produces data in json
format.
- Project Details
- API Reference
- RegEx Details
- API Response Examples
- Screenshots
- Dependencies
Java 11 (LTS)
Spring Boot 2
Maven
- Runs
Tomcat
on port:8080
- Properties file: application.properties
1. GET
GET /busses
GET /busses?engine=String
Key | Value | Description |
---|---|---|
engine |
String |
Optional. Type of bus engine. Must match one of Enum's String value. |
GET /busses/{id}
where id
is a value of a non-negative integer.
2. POST
POST /busses
- Request body pattern:
{
"id": int,
"brand": String,
"model": int || String,
"seats": int || null,
"standingRoom": int || null,
"length": int || null,
"engine": String
}
- where
int
is a non-negative integer. null
values are converted to 0s.- each
int
can be expressed as aString
as well.
3. PUT
PUT /busses/{id}
where id
is a value of a non-negative integer.
- Request body pattern:
{
"id": int,
"brand": String,
"model": int || String,
"seats": int || null,
"standingRoom": int || null,
"length": int || null,
"engine": String
}
- where
int
is a non-negative integer. null
values are converted to 0s.- each
int
can be expressed as aString
as well.
4. DELETE
DELETE /busses/{id}
where id
is a value of a non-negative integer.
RegEx
to match for id
, seats
, standingRoom
and length
:
^\d+$
Just a number or sequence of numbers between 0 and 9.
RegEx
to match for brand
:
^(?!.*[_\r\n])[a-zA-Z]([-a-zA-Z ]*[a-zA-Z])?$
To match this regex
it is necessary that:
- Provided
String
IS NOT BLANK. - Provided
String
starts and ends with any latin letter in lower or UPPER case. - Provided
String
has a single line. - Every, except FIRST and LAST, index of provided
String
can be:- A latin letter in lower or UPPER case.
- A space character.
- A dash:
—
.
RegEx
to match for model
:
^(?!.*[_\r\n])\w([-\w ]*\w)?$
To match this regex
it is necessary that:
- Provided
String
IS NOT BLANK. - Provided
String
starts and ends with a latin letter in lower or UPPER case or with any number between 0 and 9. - Provided
String
has a single line. - Every, except FIRST and LAST, index of provided
String
can be:- A latin letter in lower or UPPER case.
- Any number between 0 and 9.
- A space character.
- A dash:
—
.
RegEx
to match for engine
^((?i)\bdiesel\b+?|(?i)\belectric\b+?)*$
To match this regex
it is necessary to provide either diesel
or electric
in
CASE-INSENSITIVE variant and in a SINGLE OCCURRENCE. That means each letter of either word can be independently
in UPPER or lower case.
Let's consider valid requests at first.
-
GET /busses
-
HTTP status:
200 OK
-
Response:
[
{
"id": "1",
"brand": "Kia Motors",
"model": "Prototype 2000",
"seats": 35,
"standingRoom": 29,
"length": 16,
"engine": "DIESEL"
},
{
"id": "2",
"brand": "Daewoo Bus",
"model": "Quadrillion",
"seats": 45,
"standingRoom": 10,
"length": 6,
"engine": "ELECTRIC"
},
.,
.,
.,
{
"id": "10",
"brand": "Kia Motors",
"model": "Focus",
"seats": 33,
"standingRoom": 28,
"length": 18,
"engine": "DIESEL"
}
]
-
GET /busses?engine=ELECTRIC
-
HTTP status:
200 OK
-
Response:
[
{
"id": "2",
"brand": "Daewoo Bus",
"model": "Quadrillion",
"seats": 45,
"standingRoom": 10,
"length": 6,
"engine": "ELECTRIC"
},
{
"id": "4",
"brand": "Renault",
"model": "See-sharp",
"seats": 55,
"standingRoom": 26,
"length": 12,
"engine": "ELECTRIC"
},
.,
.,
.,
{
"id": "7",
"brand": "Scania AB",
"model": "Light",
"seats": 66,
"standingRoom": 12,
"length": 15,
"engine": "ELECTRIC"
}
]
-
GET /busses/3
-
HTTP status:
200 OK
-
Response:
{
"id": "3",
"brand": "Kia Motors",
"model": "Megane",
"seats": 41,
"standingRoom": 27,
"length": 10,
"engine": "DIESEL"
}
-
POST /busses
Request body:
{
"id": 20,
"brand": "myBrand",
"model": "myModel",
"seats": 50,
"standingRoom": 14,
"length": 8,
"engine": "eLeCtRiC"
}
- Http status:
201 Created
- Response:
{
"id": "20",
"brand": "myBrand",
"model": "myModel",
"seats": 50,
"standingRoom": 14,
"length": 8,
"engine": "ELECTRIC"
}
-
PUT /busses/20
Request body:
{
"id": "21",
"brand": "updatedBrand",
"model": "updatedModel",
"seats": 49,
"standingRoom": 0,
"length": 9,
"engine": "diesel"
}
- Http status:
200 OK
- Response:
{
"id": "20",
"brand": "updatedBrand",
"model": "updatedModel",
"seats": 49,
"standingRoom": 0,
"length": 9,
"engine": "DIESEL"
}
As we can see, once value is assigned to id
, the property became immutable.
-
DELETE /busses/20
-
Http status:
204 No Content
-
Response:
The response has no content
.
Now we are going to consider what happens if we do something wrong.
-
GET /busses/engine=myEngine
-
myEngine
DOES NOT MATCH declaredregex
-
HTTP status:
422 Unprocessable Entity
-
Response:
{
"code": 3,
"message": "Null not allowed."
}
-
GET /busses/{id}
-
PUT /busses/{id}
-
DELETE /busses/{id}
Path variable: myId
myId
DOES NOT MATCH declaredregex
, hence repository does not contain a bus with such id.- HTTP status:
404 Not Found
- Response:
{
"code": 1,
"message": "Bus with id: [myId] not found."
}
Path variable: 0
- We assume repository DOES NOT CONTAIN a bus with id:
0
- HTTP status:
404 Not Found
- Response:
{
"code": 1,
"message": "Bus with id: [0] not found."
}
-
POST /busses
Request body:
{
"id": "20",
"brand": "newBrand",
"model": "newModel",
"seats": 25,
"standingRoom": 10,
"length": 4,
"engine": "DIESEL"
}
- HTTP status:
409 Conflict
- Response:
{
"code": 2,
"message": "Bus with id: [20] already exists."
}
since we recently added a bus with id=20
.
Request body:
{
"id": "a",
"brand": "newBrand",
"model": "newModel",
"seats": 25,
"standingRoom": 10,
"length": 4,
"engine": "DIESEL"
}
- HTTP status:
422 Unprocessable Entity
- Response:
{
"code": 3,
"message": "Null not allowed."
}
since a
DOES NOT MATCH declared regex
.
Now we assume that bus with id=40
does not exist yet.
Request body:
{
"id": "40",
"brand": "?",
"model": "!",
"seats": 25,
"standingRoom": 10,
"length": 4,
"engine": "DIESEL"
}
- HTTP status:
422 Unprocessable Entity
- Response:
{
"code": 3,
"message": "not-null property references a null or transient value : com.internship.adb.busses.persistence.entity.BusEntity.brand"
}
since ?
and !
DOES NOT MATCH declared regex
.
Request body:
{
"id": "40",
"brand": "newBrand",
"model": "newModel",
"seats": "b",
"standingRoom": "c",
"length": "d",
"engine": "DIESEL"
}
- HTTP status:
400 Bad Request
- Response:
{
"code": 3,
"message": "JSON parse error: Cannot deserialize value of type `int` from String \"b\": not a valid `int` value; nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `int` from String \"b\": not a valid `int` value\n at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream); line: 5, column: 12] (through reference chain: com.internship.adb.busses.model.BusModel[\"seats\"])"
}
since b
and c
and d
DOES NOT MATCH declared regex
.
Request body:
{
"id": "40",
"brand": "newBrand",
"model": "newModel",
"seats": 25,
"standingRoom": 10,
"length": 4,
"engine": true
}
- HTTP status:
422 Unprocessable Entity
- Response:
{
"code": 3,
"message": "Null not allowed."
}
since String
value of true
DOES NOT MATCH declared regex
.
Request body:
{
"brand": "newBrand",
"model": "newModel",
"seats": 25,
"standingRoom": 10,
"length": 4,
"engine": "DIESEL"
}
- HTTP status:
422 Unprocessable Entity
- Response:
{
"code": 3,
"message": "Null not allowed."
}
since there is no occurrence of required json property
. In this case it is no occurrence of id
.
Missing Request Body:
- HTTP status:
400 Bad Request
- Response:
{
"code": 3,
"message": "Required request body is missing: public org.springframework.http.ResponseEntity<com.internship.adb.busses.model.BusModel> com.internship.adb.busses.controller.BusController.addBus(com.internship.adb.busses.model.BusModel)"
}
since request body
is required.
ArtifactId | Version |
---|---|
lombok | 1.18.24 |
spring-boot-starter-web | 2.7.5 |
spring-boot-starter-data-jpa | 2.7.5 |
h2 | 2.1.214 |
hibernate-core | 5.6.12.Final |