From 39fc655df7f2941f1e49f2bfa312a639c1aac064 Mon Sep 17 00:00:00 2001 From: Ignacio Martin Date: Fri, 6 Feb 2026 18:56:54 +0100 Subject: [PATCH 01/15] chore(gradle): upgrade Gradle wrapper from 8.9 to 8.12.1 --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 19cfad9..e382118 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 2bed20ff8ed87a05d29007573b9ef0a49cd1d33f Mon Sep 17 00:00:00 2001 From: Ignacio Martin Date: Fri, 6 Feb 2026 18:57:05 +0100 Subject: [PATCH 02/15] refactor(service): remove unused variable and import in TagService --- src/main/java/org/udg/pds/springtodo/service/TagService.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/org/udg/pds/springtodo/service/TagService.java b/src/main/java/org/udg/pds/springtodo/service/TagService.java index fb5c2dc..9afd020 100644 --- a/src/main/java/org/udg/pds/springtodo/service/TagService.java +++ b/src/main/java/org/udg/pds/springtodo/service/TagService.java @@ -7,7 +7,6 @@ import org.udg.pds.springtodo.entity.Tag; import org.udg.pds.springtodo.repository.TagRepository; -import java.util.ArrayList; import java.util.Collection; import java.util.Optional; import java.util.stream.Collectors; @@ -41,8 +40,6 @@ public Tag addTag(String name, String description) { } public Collection getTags() { - Collection r = new ArrayList<>(); - return StreamSupport.stream(tagRepository.findAll().spliterator(), false) .collect(Collectors.toList()); } From 3de44ba82830657f3933fb5c3755fd717ad8a2e7 Mon Sep 17 00:00:00 2001 From: Ignacio Martin Date: Fri, 6 Feb 2026 18:57:17 +0100 Subject: [PATCH 03/15] chore(config): add development profile configuration with database and Swagger setup --- src/main/resources/application-dev.yml | 34 ++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/main/resources/application-dev.yml diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml new file mode 100644 index 0000000..be7d546 --- /dev/null +++ b/src/main/resources/application-dev.yml @@ -0,0 +1,34 @@ +spring: + jpa: + hibernate: + naming: + physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl + ddl-auto: create-drop + database-platform: org.hibernate.dialect.MariaDBDialect + datasource: + url: jdbc:mysql://localhost:3306/pdsdb?useLegacyDatetimeCode=false + username: pdsdb + password: pdsdb + jackson: + serialization: + write-dates-as-timestamps: false # Use ISO-8601 strings, not numeric arrays + time-zone: UTC # Set default timezone + deserialization: + adjust-dates-to-context-time-zone: false # Preserve incoming timezone info + data: + rest: + detection-strategy: none # Disable Spring Data REST auto-detection + +# Swagger/OpenAPI configuration +springdoc: + api-docs: + path: /api-docs + swagger-ui: + path: /swagger-ui.html + enabled: true + operationsSorter: method + tagsSorter: alpha + packages-to-scan: org.udg.pds.springtodo.controller + paths-to-exclude: /profile, /profile/**, /**/search/** + show-actuator: false + From b8c53310dc371bf9db0a0ad91f4533f7a5111626 Mon Sep 17 00:00:00 2001 From: Ignacio Martin Date: Fri, 6 Feb 2026 18:57:26 +0100 Subject: [PATCH 04/15] feat(dto): add IdDto record for resource ID responses --- .../org/udg/pds/springtodo/dto/common/IdDto.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/main/java/org/udg/pds/springtodo/dto/common/IdDto.java diff --git a/src/main/java/org/udg/pds/springtodo/dto/common/IdDto.java b/src/main/java/org/udg/pds/springtodo/dto/common/IdDto.java new file mode 100644 index 0000000..1365a5b --- /dev/null +++ b/src/main/java/org/udg/pds/springtodo/dto/common/IdDto.java @@ -0,0 +1,14 @@ +package org.udg.pds.springtodo.dto.common; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; + +/** + * DTO for returning resource IDs + */ +public record IdDto( + @JsonProperty("id") + @NotNull + Long id +) { +} From e6351c85cd2f3fae407d5daab5f0859d679fc709 Mon Sep 17 00:00:00 2001 From: Ignacio Martin Date: Fri, 6 Feb 2026 18:57:35 +0100 Subject: [PATCH 05/15] refactor(entity): replace Lombok annotations with explicit getters and setters in User --- .../org/udg/pds/springtodo/entity/User.java | 37 ++++++++++++++++--- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/udg/pds/springtodo/entity/User.java b/src/main/java/org/udg/pds/springtodo/entity/User.java index c1a2688..c8dcaac 100644 --- a/src/main/java/org/udg/pds/springtodo/entity/User.java +++ b/src/main/java/org/udg/pds/springtodo/entity/User.java @@ -5,18 +5,12 @@ import jakarta.persistence.Entity; import jakarta.persistence.OneToMany; import jakarta.validation.constraints.NotNull; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; @Entity(name = "users") -@Data -@NoArgsConstructor -@EqualsAndHashCode(callSuper = true) public class User extends BaseEntity implements Serializable { @NotNull @@ -33,12 +27,43 @@ public class User extends BaseEntity implements Serializable { @OneToMany(cascade = CascadeType.ALL, mappedBy = "user") private Collection tasks = new ArrayList<>(); + public User() { + } + public User(String username, String email, String password) { this.username = username; this.email = email; this.password = password; } + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public Collection getTasks() { + return tasks; + } + public void addTask(Task task) { tasks.add(task); } From e3a1e4daac649914229b22f2d132f2770ec9a54b Mon Sep 17 00:00:00 2001 From: Ignacio Martin Date: Fri, 6 Feb 2026 18:57:42 +0100 Subject: [PATCH 06/15] refactor(service): replace IdObject with Long for task ID handling and remove unused imports --- src/main/java/org/udg/pds/springtodo/Global.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/udg/pds/springtodo/Global.java b/src/main/java/org/udg/pds/springtodo/Global.java index 5f1d7d2..87ec3db 100644 --- a/src/main/java/org/udg/pds/springtodo/Global.java +++ b/src/main/java/org/udg/pds/springtodo/Global.java @@ -6,9 +6,7 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import org.springframework.core.env.Environment; import org.springframework.stereotype.Service; -import org.udg.pds.springtodo.entity.IdObject; import org.udg.pds.springtodo.entity.Tag; import org.udg.pds.springtodo.entity.User; import org.udg.pds.springtodo.service.TagService; @@ -88,9 +86,9 @@ private void initData() { logger.info("Starting populating database ..."); User user = userService.register("usuari", "usuari@hotmail.com", "123456"); - IdObject taskId = taskService.addTask("Una tasca", user.getId(), ZonedDateTime.now(), ZonedDateTime.now()); + Long taskId = taskService.addTask("Una tasca", user.getId(), ZonedDateTime.now(), ZonedDateTime.now()); Tag tag = tagService.addTag("ATag", "Just a tag"); - taskService.addTagsToTask(user.getId(), taskId.id, new ArrayList() {{ + taskService.addTagsToTask(user.getId(), taskId, new ArrayList() {{ add(tag.getId()); }}); userService.register("user", "user@hotmail.com", "0000"); From e8102db35de2fb6acf2765296ce0963d88d0131c Mon Sep 17 00:00:00 2001 From: Ignacio Martin Date: Fri, 6 Feb 2026 18:57:50 +0100 Subject: [PATCH 07/15] refactor(entity): replace Lombok annotations with explicit getters in Tag --- .../java/org/udg/pds/springtodo/entity/Tag.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/udg/pds/springtodo/entity/Tag.java b/src/main/java/org/udg/pds/springtodo/entity/Tag.java index f0ac6ab..cae7a6c 100644 --- a/src/main/java/org/udg/pds/springtodo/entity/Tag.java +++ b/src/main/java/org/udg/pds/springtodo/entity/Tag.java @@ -2,16 +2,10 @@ import jakarta.persistence.Entity; import jakarta.validation.constraints.NotNull; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; import java.io.Serializable; @Entity -@Data -@NoArgsConstructor -@EqualsAndHashCode(callSuper = true) public class Tag extends BaseEntity implements Serializable { @NotNull @@ -20,9 +14,20 @@ public class Tag extends BaseEntity implements Serializable { @NotNull private String description; + public Tag() { + } + public Tag(String name, String description) { this.name = name; this.description = description; } + public String getName() { + return name; + } + + public String getDescription() { + return description; + } + } From 97a8c5a293d0b4b101e9ae2dbc97856dfbf3eab6 Mon Sep 17 00:00:00 2001 From: Ignacio Martin Date: Fri, 6 Feb 2026 18:57:58 +0100 Subject: [PATCH 08/15] refactor(entity): replace Lombok annotations with explicit getters and setters in Task --- .../org/udg/pds/springtodo/entity/Task.java | 39 +++++++++++++++---- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/udg/pds/springtodo/entity/Task.java b/src/main/java/org/udg/pds/springtodo/entity/Task.java index 6f62df0..8a7548b 100644 --- a/src/main/java/org/udg/pds/springtodo/entity/Task.java +++ b/src/main/java/org/udg/pds/springtodo/entity/Task.java @@ -1,20 +1,12 @@ package org.udg.pds.springtodo.entity; import jakarta.persistence.*; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; - import java.io.Serializable; import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Collection; @Entity -// This tells JAXB that it has to ignore getters and setters and only use fields for JSON marshaling/unmarshaling -@Data -@NoArgsConstructor -@EqualsAndHashCode(callSuper = true) public class Task extends BaseEntity implements Serializable { @ManyToMany @@ -34,6 +26,9 @@ public class Task extends BaseEntity implements Serializable { @JoinColumn(name = "user_owner") private User user; + public Task() { + } + public Task(ZonedDateTime dateCreated, ZonedDateTime dateLimit, Boolean completed, String text) { this.dateCreated = dateCreated; this.dateLimit = dateLimit; @@ -41,7 +36,35 @@ public Task(ZonedDateTime dateCreated, ZonedDateTime dateLimit, Boolean complete this.text = text; } + public ZonedDateTime getDateCreated() { + return dateCreated; + } + + public ZonedDateTime getDateLimit() { + return dateLimit; + } + + public Boolean getCompleted() { + return completed; + } + + public String getText() { + return text; + } + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + public void addTag(Tag tag) { tags.add(tag); } + + public Collection getTags() { + return tags; + } } From 01f7990b3a55b57ac41aebfe1cda784f882d3380 Mon Sep 17 00:00:00 2001 From: Ignacio Martin Date: Fri, 6 Feb 2026 18:58:05 +0100 Subject: [PATCH 09/15] refactor(service): return Long instead of IdObject from addTask method --- .../java/org/udg/pds/springtodo/service/TaskService.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/udg/pds/springtodo/service/TaskService.java b/src/main/java/org/udg/pds/springtodo/service/TaskService.java index 20bb9dd..524aefc 100644 --- a/src/main/java/org/udg/pds/springtodo/service/TaskService.java +++ b/src/main/java/org/udg/pds/springtodo/service/TaskService.java @@ -4,7 +4,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.udg.pds.springtodo.configuration.exceptions.ServiceException; -import org.udg.pds.springtodo.entity.IdObject; import org.udg.pds.springtodo.entity.Tag; import org.udg.pds.springtodo.entity.Task; import org.udg.pds.springtodo.entity.User; @@ -37,7 +36,7 @@ public Task getTask(Long userId, Long id) { } @Transactional - public IdObject addTask(String text, Long userId, + public Long addTask(String text, Long userId, ZonedDateTime created, ZonedDateTime limit) { try { User user = userService.getUser(userId); @@ -49,7 +48,7 @@ public IdObject addTask(String text, Long userId, user.addTask(task); taskRepository.save(task); - return new IdObject(task.getId()); + return task.getId(); } catch (Exception ex) { // Very important: if you want that an exception reaches the EJB caller, you have to throw an ServiceException // We catch the normal exception and then transform it in a ServiceException From 47d7871fb70303908fff4bbd4a666e269e43ac17 Mon Sep 17 00:00:00 2001 From: Ignacio Martin Date: Fri, 6 Feb 2026 18:58:14 +0100 Subject: [PATCH 10/15] chore(config): remove application-dev.properties in favor of YAML configuration --- src/main/resources/application-dev.properties | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 src/main/resources/application-dev.properties diff --git a/src/main/resources/application-dev.properties b/src/main/resources/application-dev.properties deleted file mode 100644 index 38ba7e2..0000000 --- a/src/main/resources/application-dev.properties +++ /dev/null @@ -1,6 +0,0 @@ -spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl -spring.jpa.hibernate.ddl-auto=create-drop -spring.datasource.url=jdbc:mysql://localhost:3306/pdsdb?useLegacyDatetimeCode=false -spring.datasource.username=pdsdb -spring.datasource.password=pdsdb -spring.jpa.database-platform=org.hibernate.dialect.MariaDBDialect From 671bc404df991b880df98d141c849d1271e8fb31 Mon Sep 17 00:00:00 2001 From: Ignacio Martin Date: Fri, 6 Feb 2026 18:58:24 +0100 Subject: [PATCH 11/15] refactor(entity): remove IdObject class replaced by Long and IdDto --- .../org/udg/pds/springtodo/entity/IdObject.java | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 src/main/java/org/udg/pds/springtodo/entity/IdObject.java diff --git a/src/main/java/org/udg/pds/springtodo/entity/IdObject.java b/src/main/java/org/udg/pds/springtodo/entity/IdObject.java deleted file mode 100644 index 1b10049..0000000 --- a/src/main/java/org/udg/pds/springtodo/entity/IdObject.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.udg.pds.springtodo.entity; - -import org.springframework.lang.NonNull; - -public class IdObject { - - @NonNull - public Long id; - - public IdObject(@NonNull Long id) { - this.id = id; - } -} From f44ab4046b3bef3759292df33e99102e7ef936ca Mon Sep 17 00:00:00 2001 From: Ignacio Martin Date: Fri, 6 Feb 2026 18:58:37 +0100 Subject: [PATCH 12/15] refactor(entity): replace Lombok annotations with explicit getter in BaseEntity --- .../java/org/udg/pds/springtodo/entity/BaseEntity.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/udg/pds/springtodo/entity/BaseEntity.java b/src/main/java/org/udg/pds/springtodo/entity/BaseEntity.java index c01595b..0a5c5fe 100644 --- a/src/main/java/org/udg/pds/springtodo/entity/BaseEntity.java +++ b/src/main/java/org/udg/pds/springtodo/entity/BaseEntity.java @@ -5,16 +5,15 @@ import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.MappedSuperclass; -import lombok.AccessLevel; -import lombok.Data; -import lombok.Setter; @MappedSuperclass -@Data public class BaseEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Setter(AccessLevel.NONE) protected Long id; + + public Long getId() { + return id; + } } From 716a65814f7eedf30f8ff6f8d1a2492bbad70e74 Mon Sep 17 00:00:00 2001 From: Ignacio Martin Date: Fri, 6 Feb 2026 18:58:45 +0100 Subject: [PATCH 13/15] chore(deps): upgrade Spring Boot to 3.5.10, Java to 21, add OpenAPI support and update MapStruct --- build.gradle | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/build.gradle b/build.gradle index 5e7f9b9..8b8602c 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ buildscript { plugins { id 'java' id 'idea' - id 'org.springframework.boot' version "3.4.4" + id 'org.springframework.boot' version "3.5.10" } apply plugin: 'io.spring.dependency-management' @@ -27,15 +27,14 @@ ext { mapstructVersion = "1.6.3" } -sourceCompatibility = 1.17 -targetCompatibility = 1.17 +sourceCompatibility = 21 +targetCompatibility = 21 dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-validation' // JPA Data (We are going to use Repositories, Entities, Hibernate, etc...) - implementation 'org.springframework.boot:spring-boot-starter-data-rest' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-data-jdbc' implementation 'org.springframework.boot:spring-boot-starter-actuator' @@ -53,7 +52,10 @@ dependencies { implementation "org.mapstruct:mapstruct:${mapstructVersion}" annotationProcessor "org.mapstruct:mapstruct-processor:${mapstructVersion}" - implementation 'org.mapstruct.extensions.spring:mapstruct-spring-extensions:1.1.3' - implementation 'org.mapstruct.extensions.spring:mapstruct-spring-annotations:1.1.3' + implementation 'org.mapstruct.extensions.spring:mapstruct-spring-extensions:2.0.0' + implementation 'org.mapstruct.extensions.spring:mapstruct-spring-annotations:2.0.0' + + // Swagger/OpenAPI documentation + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.4' } From 2b2ad19263b2533d9dbdea151d8f46ffd84361c0 Mon Sep 17 00:00:00 2001 From: Ignacio Martin Date: Fri, 6 Feb 2026 18:58:54 +0100 Subject: [PATCH 14/15] feat(config): add OpenAPI configuration for API documentation --- .../configuration/OpenApiConfig.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/main/java/org/udg/pds/springtodo/configuration/OpenApiConfig.java diff --git a/src/main/java/org/udg/pds/springtodo/configuration/OpenApiConfig.java b/src/main/java/org/udg/pds/springtodo/configuration/OpenApiConfig.java new file mode 100644 index 0000000..6ff5a32 --- /dev/null +++ b/src/main/java/org/udg/pds/springtodo/configuration/OpenApiConfig.java @@ -0,0 +1,27 @@ +package org.udg.pds.springtodo.configuration; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Contact; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.License; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class OpenApiConfig { + + @Bean + public OpenAPI customOpenAPI() { + return new OpenAPI() + .info(new Info() + .title("TODO Spring API") + .version("1.0") + .description("REST API documentation for the TODO Spring application") + .contact(new Contact() + .name("UdG PDS") + .email("pds@udg.edu")) + .license(new License() + .name("MIT License") + .url("https://opensource.org/licenses/MIT"))); + } +} From 5da1ed15e23ba79356077b2a55307e0cda2167f8 Mon Sep 17 00:00:00 2001 From: Ignacio Martin Date: Fri, 6 Feb 2026 18:59:07 +0100 Subject: [PATCH 15/15] refactor(controller): replace IdObject with IdDto and add field validation in TaskController --- .../pds/springtodo/controller/TaskController.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/udg/pds/springtodo/controller/TaskController.java b/src/main/java/org/udg/pds/springtodo/controller/TaskController.java index 91ed04b..96506df 100644 --- a/src/main/java/org/udg/pds/springtodo/controller/TaskController.java +++ b/src/main/java/org/udg/pds/springtodo/controller/TaskController.java @@ -2,8 +2,10 @@ import jakarta.servlet.http.HttpSession; import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.format.annotation.DateTimeFormat; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import org.udg.pds.springtodo.dto.Tag.TagDto; @@ -11,7 +13,7 @@ import org.udg.pds.springtodo.dto.Task.TaskDto; import org.udg.pds.springtodo.dto.Task.TaskFullDto; import org.udg.pds.springtodo.dto.Task.TaskMapper; -import org.udg.pds.springtodo.entity.IdObject; +import org.udg.pds.springtodo.dto.common.IdDto; import org.udg.pds.springtodo.service.TaskService; import java.time.ZonedDateTime; @@ -48,11 +50,12 @@ public Collection listAllTasks(HttpSession session, } @PostMapping(consumes = "application/json") - public IdObject addTask(HttpSession session, @Valid @RequestBody R_Task task) { + public IdDto addTask(HttpSession session, @Valid @RequestBody R_Task task) { Long userId = getLoggedUser(session); - return taskService.addTask(task.text, userId, task.dateCreated, task.dateLimit); + Long taskId = taskService.addTask(task.text, userId, task.dateCreated, task.dateLimit); + return new IdDto(taskId); } @DeleteMapping(path = "/{id}") @@ -83,12 +86,15 @@ public Collection getTaskTags(HttpSession session, static class R_Task { @NotNull + @NotBlank public String text; @NotNull + @DateTimeFormat public ZonedDateTime dateCreated; @NotNull + @DateTimeFormat public ZonedDateTime dateLimit; }