How to validate yaml and yml files in springboot? - spring-boot

In the project I have been working on we use yaml files to automatically create our responses and requests kotlin classes. for example:
title: Student
type: object
properties:
id:
type: number
name:
type: string
Since the classes are created automatically I cannot add any annotations because everytime I build my application the files will be created again and the old ones will be deleted.
How can I validate the properties (#NotBlank, #Min, #Max, #Positive, etc) in the yaml files?
The only one I have used is 'required' to set the required properties.

You could use a combination of jackson-dataformat-yaml and javax.validation.constraints.
Dependency:
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
<version>2.13.0</version>
</dependency>
Model code:
import javax.validation.constraints.NotBlank;
public class TopLevel {
#NotBlank
String title;
#NotBlank
String type;
#NotBlank
Property properties;
}
import javax.validation.constraints.NotBlank;
public class Property {
#NotBlank
String id;
}

Related

javax-validation annotation is not working for member variables that is declared as another ObjectType

I have added annotations in the parent class.
It is working fine.
But it is not working in the member variables that is declared as another Object type. It is validating:
orderId from base class
referenceNumber from MarchantApplicationRequest
#NotEmpty annotation at customerRequests field in MerchantApplicationRequest.
But it is not validating customerRoleType in CustomerRequest.
Also, I would like to add #NotBlank annotation in customerRequests. But it is not taking this, though it is taking #NotEmpty annotation.
Class MerchantApplicationRequest
#JsonIngnoreProperties(ignoreUnknown=false)
public class MerchantApplicationRequest extends IomBaseDTO {
#NotEmpty(message="customerRequests is mandatory")
private List<CustomerRequest> customerRequests;
#NotBlank(message="referenceNumber is mandatory")
private String referenceNumber ;
}
Class CustomerRequest
public class CustomerRequest {
#NotBlank(message="customerRoleType is mandatory")
private String customerRoleType ;
}
Controller class
Method where to apply validation:
#PostMapping("/orderDetail")
public void orderDetail(#Valid #RequestBody MerchantApplicationRequest request) {
try {
iOrderService.updateProductDetail(request);
} catch (Exception e) {
// ...
}
}
Here is my JSON payload:
{
"orderId" : 101,
"referenceNumber" : "123",
"customerRequests" : [ {
"customerRoleType" : null
}]
}
I am using in pom.xml of Spring Boot application:
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
If you want to cascade the validation you have to add the #Valid annotation:
#Valid
#NotEmpty(message="customerRequests is mandatory")
private List<CustomerRequest> customerRequests;
Please read more about cascading in the Hibernate Validation documentation: Example 2.11: Cascaded validation
Using bean-validation (javax.validation), you can add validation to elements of collections.
Using Bean-Validation 1.0
#JsonIngnoreProperties(ignoreUnknown=false)
public class MerchantApplicationRequest extends IomBaseDTO {
#NotEmpty(message="customerRequests is mandatory")
#Valid
private List<CustomerRequest> customerRequests;
#NotBlank(message="referenceNumber is mandatory")
private String referenceNumber ;
}
See also:
JSR 303: How to Validate a Collection of annotated objects?
LogicBig Tutorial: Collection Validation
Alternative since Bean-Validation 2.0
In Java 8 generic types can also be validated by prepending the annotation before the type inside the diamond-operator, e.g. <#Valid CustomerRequest>. This is a more concise way of defining per-element validation. It has the same effect like the traditional way, validates every given element as defined in the class (CustomerRequest).
See also:
java/beans validation - collection/map does not contain nulls
Baeldung Tutorial: Validating Container Elements with Bean Validation 2.0

Setting date format output in spring rest with gson

I have a legacy application which uses Spring-Rest and Google-GSON (declared in pom.xml) for serializing/deserializing Objects. In one of these objects there's a java.util.Date property, I want to set the date format but I cannot find how to do it.
I can't even switch to Jackson because a colleague of mine uses it explicitly in a part of his code.
How can I set the date format in this scenario?
This application doesn't use Spring Boot. Everything I found for this problem is about Spring-boot + Jackson.
EDIT: I add some details. I have this Class:
#Entity
#Table(name="WEB_ELENCO_SCHEMI")
#IdClass(PK.class)
public class WebElencoSchemi implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name="COD_ARCHIVIO_ARCAM")
private BigDecimal codArchivioArcam;
#Temporal(TemporalType.DATE)
#Column(name="DATA_AGGIORNAM")
private Date dataAggiornam;
...
}
And this repository:
public interface WebElencoSchemiRepository extends CrudRepository<WebElencoSchemi, BigDecimal> {
public List<WebElencoSchemi> findByCodArchivioArcam(BigDecimal codArchivioArcam);
I want to set the format of dataAggiornam JSON output. I'm using GSON as serializator/deserializator for Spring Rest, as defined in pom.xml.
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.2.4</version>
</dependency>
I tried adding a spring.gson.date-format property in my properties file with no success.
I'm NOT using Spring boot and I cannot switch to Jackson (in which the problem is solved with a simple annotation on the class property).
You can set a date format while creating the Gson object with the GsonBuilder.
Something like;
Gson gson = new GsonBuilder().setDateFormat("dd/MM/yyyy HH:mm").serializeNulls().create();
It has a bunch of other factory methods which are super useful also, for your perusal. Love this library.

Make XML payload fields case insensitive when mapping to Java Object in REST API developed using SpringBoot

Because of history reason, we must adapt old sys. This is the xml request:
<?xml version="1.0" encoding="UTF-8"?>
<User>
<Age>18</Age>
<Gender>Male</Gender>
<PassWord>string</PassWord>
<UserName>
<FirstName>Maxwell</FirstName>
<LastName>xxx</LastName>
<MiddleName>string</MiddleName>
</UserName>
</User>
Now, we need to implemente the consumer-service with springboot. But it didn't support payload case insensitive when mapping to bean.
#Data
public class User{
private Username UserName;
private String PassWord;
private int Age;
private String Gender;
#Data
class UserName{
private String LastName;
private String MiddleName;
private String FirstName;
}
}
Result:
I know I could use #XmlElement, but it will have some issue when integrate with swagger #annotation.
I would like to map the XML payload to Java Object directly using #RequestBody Spring annotation. My question here is How do I make the java Object to map to the fields ignoring the case.
I found the way to handle this issue. We could import jackson-dataformat-xml into pom.xml
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.9.6</version>
</dependency>
If don’t use jackson-dataformat-xml, SpringBoot automatically uses JAXB of JDK to convert XML. It will case sensitive.
Call .configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true) to the ObjectMapper to be case-insensitive.

JaversException PROPERTY_NOT_FOUND: Property in derived class not found in abstract class

I have a model looking something like this:
#Data
public abstract class InputFormGroup
{
String id;
String name;
String text;
String type;
}
#Data
public class SimpleInputFormGroup extends InputFormGroup
{
InputControl inputControl;
InputFormAnswerRow answerRow;
}
#Data
public class InputFormPage
{
String id;
String name;
String title;
List<InputFormGroup> inputFormGroups = new LinkedList<>();
}
In effect I have a larger structure that in it has InputFormPages that has one or more InputFormGroups that can be of type SimpleInputFormGroup (and also other types that I have not included in this example).
Im using MongoRepository to persist them and everything looks very nice and I can query the changes on the Entity object and it all looks good.
The only time I have an issue is when I try to query with a path. In this example "..../inputFormPages/0/inputFormGroups/0/answerRow/answers/0".
Then I get the exception because the framework finds a list of InputFormGroup but then when it looks for answerRow in the abstract InputFormGroup base class it does naturally not find it. Is there some way to configure the model so the framework also looks in the derived classes for, in this case, the answerRow parameter? Of is it as simple as the framework doesn't support polymorphism in this way?
The error I got:
"JaversException PROPERTY_NOT_FOUND: Property 'answerRow' not found in class 'com.replior.ebrmockupbackend.model.InputFormGroup'. If the name is correct - check annotations. Properties with #DiffIgnore or #Transient are not visible for JaVers."
And the Query:
JqlQuery query = QueryBuilder.byValueObjectId(batch1.getId(),Batch.class,"inputForm/inputFormSteps/2/inputFormPages/0/inputFormGroups/0/answerRow/answers/0").withChangedProperty("value").build();
List<Change> changes = javers.findChanges(query);
And the version:
<dependency>
<groupId>org.javers</groupId>
<artifactId>javers-spring-boot-starter-mongo</artifactId>
<version>3.10.2</version>
</dependency>
Appreciate any help I can get.
Link to project that exemplifies the issue:
Github project
This issue is fixed in JaVers 3.11.3

How to map user data type in cassandra using spring boot data

I am looking out for some help related with spring boot data using Cassandra database.
I have following dependencies in my pom.xml.
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-boot-starter-data-cassandra</artifactId>
</dependency>
<dependency>
<groupId>com.datastax.cassandra</groupId>
<artifactId>cassandra-driver-core</artifactId>
<version>2.1.10.3</version>
</dependency>
<dependency>
<groupId>com.datastax.cassandra</groupId>
<artifactId>cassandra-driver-mapping</artifactId>
<version>2.1.10.3</version>
</dependency>
The table structure looks like:
#Table(value = "TEST_ORDERS")
public class OrderDTO {
#PrimaryKey
#Column(value = "email")
private String emailId;
#Column(value = "order_id")
private int orderId;
#Column(value = "creation_date")
private Timestamp creationDate;
#Column(value = "discount_total")
private double discountTotal;
#Column(name = "shipments")
//This is a UDT type
private Set<ShippingDetails> shipments;
//getters and setters here
}
The ShippingDetails object is a UDT with following declartion and i defined as a frozen collection in the cassandra CQL sripts
#UDT(name = "shipping", keyspace = "mc_checkout")
public class ShippingDetails {
#Field(name = "name")
private FullName name;
#Field(name = "quantity_shipped")
private int quantityShipped;
#Field(name = "shipping_address")
private CheckoutAddress shippingAddress;
//so on
}
There is a repository created for the basic CRUD operations:
#Repository
public interface OrderRepository extends CrudRepository<OrderDTO, String> {
}
When i try to invoke findOne API of this repository in my Service class
i get below error:
Cassandra entities must have the #Table, #Persistent or #PrimaryKeyClass Annotation
Spring Data for Apache Cassandra and Datastax' Mapping are two independent tools that try to accomplish the same. Please use either one but don't mix these.
CrudRepository is a Spring Data type while #Field and #UDT are coming from Datastax Mapping.
UDT support for Spring Data for Apache Cassandra is available as of version 1.5, see reference docs. Spring Data for Apache Cassandra 1.5 requires Datastax Java Driver 3.0 or newer.

Resources