Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat : use SQLStatementValidator and ValidationGroups #1593

Merged
merged 6 commits into from
Dec 22, 2024
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ The following table list all sample codes related to the spring boot integration
| [Rabbit Mq Implementation](./boot-rabbitmq-thymeleaf) | The application, demonstrates how rabbitmq works with producer side acknowledgement | Completed |
| [Spring Batch Implementation](./batch-boot-jpa-sample) | The application, demonstrates implementing Spring Batch 5 using simple config and creating batch tables using liquibase | Completed |
| [Rest API Documentation with examples](./boot-rest-docs-sample) | This application, demonstrates ability to generate pdf API documentation using spring rest docs | Completed |
| [Custom SequenceNumber and LazyConnectionDataSourceProxy for db connection improvement](./jpa/boot-data-customsequence) | This application, demonstrated ability to create custom sequences, using datasource-proxy and LazyConnectionDataSourceProxy for db connection improvement using mariadb | Completed |
| [Custom SequenceNumber and LazyConnectionDataSourceProxy for db connection improvement](./jpa/boot-data-customsequence) | This application demonstrates: Custom sequence generation, Database connection optimization using datasource-proxy and LazyConnectionDataSourceProxy with MariaDB, SQL query validation using SQLStatementCountValidator, Dynamic validation using ValidationGroups | Completed |
| [KeySet pagination and dynamic search](./jpa/keyset-pagination/blaze-persistence) | Implements KeySet Pagination using Blaze Persistence and enable dynamic search using specifications | Completed |

For More info about this repository, Please visit [here](https://rajadilipkolli.github.io/my-spring-boot-experiments/)
Expand Down
5 changes: 0 additions & 5 deletions jpa/boot-data-customsequence/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,6 @@
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>

<!-- database related dependencies -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,66 @@
package com.example.custom.sequence.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;

@Data
@ConfigurationProperties("application")
public class ApplicationProperties {
private Cors cors = new Cors();

@Data
@NestedConfigurationProperty private Cors cors = new Cors();

public Cors getCors() {
return cors;
}

public void setCors(Cors cors) {
this.cors = cors;
}

public static class Cors {
private String pathPattern = "/api/**";
private String allowedMethods = "*";
private String allowedHeaders = "*";
private String allowedOriginPatterns = "*";
private boolean allowCredentials = true;

public String getPathPattern() {
return pathPattern;
}

public void setPathPattern(String pathPattern) {
this.pathPattern = pathPattern;
}

public String getAllowedMethods() {
return allowedMethods;
}

public void setAllowedMethods(String allowedMethods) {
this.allowedMethods = allowedMethods;
}

public String getAllowedHeaders() {
return allowedHeaders;
}

public void setAllowedHeaders(String allowedHeaders) {
this.allowedHeaders = allowedHeaders;
}

public String getAllowedOriginPatterns() {
return allowedOriginPatterns;
}

public void setAllowedOriginPatterns(String allowedOriginPatterns) {
this.allowedOriginPatterns = allowedOriginPatterns;
}

public boolean isAllowCredentials() {
return allowCredentials;
}

public void setAllowCredentials(boolean allowCredentials) {
this.allowCredentials = allowCredentials;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
package com.example.custom.sequence.config;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
@Slf4j
public class Initializer implements CommandLineRunner {

private static final Logger log = LoggerFactory.getLogger(Initializer.class);
private final ApplicationProperties properties;

Check warning on line 12 in jpa/boot-data-customsequence/src/main/java/com/example/custom/sequence/config/Initializer.java

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Field can be local

Field can be converted to a local variable

public Initializer(ApplicationProperties properties) {
this.properties = properties;
}

@Override
public void run(String... args) {
log.info("Running Initializer.....");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
package com.example.custom.sequence.config;

import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration(proxyBeanMethods = false)
@RequiredArgsConstructor
public class WebMvcConfig implements WebMvcConfigurer {

private final ApplicationProperties properties;

public WebMvcConfig(ApplicationProperties properties) {
this.properties = properties;
}

@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping(properties.getCors().getPathPattern())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.example.custom.sequence.config;
package com.example.custom.sequence.config.db;

import io.hypersistence.utils.spring.repository.BaseJpaRepositoryImpl;
import org.springframework.context.annotation.Configuration;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.example.custom.sequence.config;
package com.example.custom.sequence.config.db;

import io.hypersistence.utils.logging.InlineQueryLogEntryCreator;
import javax.sql.DataSource;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.example.custom.sequence.config;
package com.example.custom.sequence.config.db;

import java.io.Serializable;
import java.lang.reflect.Member;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.example.custom.sequence.config;
package com.example.custom.sequence.config.db;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.example.custom.sequence.entities;

import com.example.custom.sequence.config.StringPrefixedSequence;
import com.example.custom.sequence.config.db.StringPrefixedSequence;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
Expand All @@ -12,18 +12,10 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.hibernate.Hibernate;

@Entity
@Table(name = "customers")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class Customer {

@Id
Expand All @@ -37,22 +29,59 @@
@OneToMany(mappedBy = "customer", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Order> orders = new ArrayList<>();

public Customer() {}

public Customer(String id, String text, List<Order> orders) {
this.id = id;
this.text = text;
this.orders = orders;
}

public Customer(String text) {
this.text = text;
}

public void addOrder(Order order) {
public String getId() {
return id;
}

public Customer setId(String id) {
this.id = id;
return this;
}

public String getText() {
return text;
}

public Customer setText(String text) {
this.text = text;
return this;
}

public List<Order> getOrders() {
return orders;
}

public Customer setOrders(List<Order> orders) {
this.orders = orders;
return this;
}

public Customer addOrder(Order order) {
orders.add(order);
order.setCustomer(this);
return this;
}

public void removeOrder(Order removedOrder) {
public Customer removeOrder(Order removedOrder) {
orders.remove(removedOrder);
removedOrder.setCustomer(null);
return this;
}

@Override
public boolean equals(Object o) {

Check warning on line 84 in jpa/boot-data-customsequence/src/main/java/com/example/custom/sequence/entities/Customer.java

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

'equals()' method which does not check class of parameter

`equals()` should check the class of its parameter
if (this == o) return true;
if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) return false;
Customer customer = (Customer) o;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.example.custom.sequence.entities;

import com.example.custom.sequence.config.StringPrefixedSequence;
import com.example.custom.sequence.config.db.StringPrefixedSequence;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
Expand All @@ -11,18 +11,10 @@
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.util.Objects;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.hibernate.Hibernate;

@Entity
@Table(name = "orders")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class Order {

@Id
Expand All @@ -37,8 +29,43 @@
@JoinColumn(name = "customer_id")
private Customer customer;

public Order() {}

public Order(String id, String text, Customer customer) {
this.id = id;
this.text = text;
this.customer = customer;
}

public String getId() {
return id;
}

public Order setId(String id) {
this.id = id;
return this;
}

public String getText() {
return text;
}

public Order setText(String text) {
this.text = text;
return this;
}

public Customer getCustomer() {
return customer;
}

public Order setCustomer(Customer customer) {
this.customer = customer;
return this;
}

@Override
public boolean equals(Object o) {

Check warning on line 68 in jpa/boot-data-customsequence/src/main/java/com/example/custom/sequence/entities/Order.java

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

'equals()' method which does not check class of parameter

`equals()` should check the class of its parameter
if (this == o) return true;
if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) return false;
Order order = (Order) o;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ public CustomerResponse mapToResponse(Customer saved) {

public Customer mapToEntity(CustomerRequest customerRequest) {
Customer customer = new Customer(customerRequest.text());
if (customerRequest.orders() == null) {
return customer;
}
customerRequest
.orders()
.forEach(orderRequest -> customer.addOrder(orderMapper.mapToEntity(orderRequest)));
Expand All @@ -38,6 +41,9 @@ public Customer mapToEntity(CustomerRequest customerRequest) {

public void updateCustomerFromRequest(CustomerRequest customerRequest, Customer foundCustomer) {
foundCustomer.setText(customerRequest.text());
if (customerRequest.orders() == null) {
return;
}
List<Order> removedOrders = new ArrayList<>(foundCustomer.getOrders());
List<Order> ordersFromRequest =
customerRequest.orders().stream()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.example.custom.sequence.model.request;

import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import java.util.List;

public record CustomerRequest(
@NotBlank(message = "Text cannot be empty") String text, List<OrderRequest> orders) {}
@NotBlank(message = "Text cannot be empty") String text,
@Valid List<OrderRequest> orders) {}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.example.custom.sequence.model.request;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;

public record OrderRequest(
@NotEmpty(message = "Text cannot be empty") String text,
@NotBlank(message = "CustomerId cannot be blank") String customerId) {}
@NotBlank(message = "Text cannot be empty") String text,
@NotBlank(
message = "CustomerId cannot be blank",
groups = ValidationGroups.GroupCheck.class)
String customerId) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.example.custom.sequence.model.request;

public interface ValidationGroups {

interface SkipGroupCheck {}

interface GroupCheck {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,11 @@ public Optional<CustomerResponse> updateCustomerById(
}

@Transactional
public void deleteCustomerById(String id) {
customerRepository.deleteById(id);
public Optional<CustomerResponse> deleteCustomerById(String id) {
Optional<CustomerResponse> optionalCustomer = findCustomerById(id);
optionalCustomer.ifPresent(
customerResponse -> customerRepository.deleteById(customerResponse.id()));
return optionalCustomer;
}

public Optional<Customer> findById(String customerId) {
Expand Down
Loading
Loading