I want to render the data format of my choice dynamically in REST api - spring-boot

I have to render the data format of my choice at run time.
E.x.
public class Message {
#Id
private String version;
private String title;
private String content;
private String sender;
private String url;
}
now if i hit the url http://localhost:8080/messages/12345/xml it should return xml format
and if i hit the url http://localhost:8080/messages/12345/json then i should return json format
but the end point should be same
http://localhost:8080/messages/12345
I am very new to Spring boot and REST ,it would be a great help.

Based on your question, for json you don't need a converter or libraries spring boot have jackson library so it will automatically converts your pojo into json. For xml response add jackson-dataformat-xml dependency to your project
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.9.8</version>
</dependency>
and while returning response convert pojo to xml response like this
Message message = new Message();
message.setVersion();
// set all the values if you want otherwise take the message object and pass
XmlMapper xmlMapper = new XmlMapper();
String xml = xmlMapper.writeValueAsString(message);
This will return xml response

Related

Flattening RequestParam Object in OpenApi 3

I am migrating from swagger 2 to OpenApi 3.
Swagger 2 Sample Code
#ApiOperation(value = "", nickname = "")
#GetMapping
public List<Employee> findEmployees(#Valid Dto dto) {
return employeeService.findEmployees(dto);
}
OpenApi 3 Code
#Operation(summary = "")
#GetMapping
public List<Employee> findEmployees(#Valid Dto dto) {
return employeeService.findEmployees(dto);
}
DTO Class
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
public class Dto {
private String status;
private String name;
private String destination;
}
There is a significant difference in generation of swagger-ui in both cases.
Swagger 2 shows the DTO object as flattened into individual query params :
Image Flattening of object as individual query parameters happens in Swagger 2 ui
while OpenApi 3 creates a JSON object:
Image Object doesnot flattens but creates a json object
I want to have the flattening behavior in OpenApi 3 like the way it used to be in Swagger 2.
Is there any way to achieve the same in OPENAPI 3.
After some research i found that a new version of openapiui dependency has been released on 12th of april 2020 and it solves my issue in hand. From version 1.3.2 its available.
<!-- https://mvnrepository.com/artifact/org.springdoc/springdoc-openapi-ui -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.3.2</version>
</dependency>
The use of Annotation #ParameterObject before the query parameter object solves it.
#Operation(summary = "")
#GetMapping
public List<Employee> findEmployees(**#ParameterObject** #Valid Dto dto) {
return employeeService.findEmployees(dto);
}

How do you save files for entity in Spring Data Rest?

In a regular entity for SDR, it takes care of all properties of an entity for you saving it to the database. But how do you handle files?
#Entity
public class User {
String name;
Set<File> myfiles; //how can I make this work?
}
#RepositoryRestResource
public interface UserRepository extends JpaRepository<User, Long> {}
How can I make it so that a User owns a list of files, can upload and download them?
This is not really possible with Spring Data/REST as it focusses on structured data; i.e. tables and associations, for the most part.
#Lob is problematic as it forces you to store your content in the database which isn't necessarily where you want to store it. The file-system or S3 might be better for example.
byte[] is also problematic if you have very large files as you will likely cause OutOfMemoryExceptions.
Instead, there is a community project called Spring Content that addresses exactly the problem you are trying to solve.
Spring Content provides the same programming paradigms as Spring Data/REST for unstructured data; i.e. images, documents, movies, etc. So, using this project you can associate one, or in your case, many "content" objects with your Spring Data entities and manage them over HTTP just like you do with your Spring Data Entities too.
Its pretty simple to add to your project, as follows:
pom.xml (boot starters also available)
<!-- Java API -->
<dependency>
<groupId>com.github.paulcwarren</groupId>
<artifactId>spring-content-fs</artifactId>
<version>1.0.0.M4</version>
</dependency>
<!-- REST API -->
<dependency>
<groupId>com.github.paulcwarren</groupId>
<artifactId>spring-content-rest</artifactId>
<version>1.0.0.M4</version>
</dependency>
Configuration
#Configuration
#EnableFilesystemStores
#Import("org.springframework.content.rest.config.RestConfiguration.class")
public class ContentConfig {
#Bean
FileSystemResourceLoader fileSystemResourceLoader() throws IOException {
return new FileSystemResourceLoader(new File("/path/to/uploaded/files").getAbsolutePath());
}
}
To associate content, modify your User entity as follows:
#Entity
public class User {
String name;
List<Image> images;
}
Add an Image entity:
#Entity
public class Image {
#ContentId
private String contentId;
#ContentLength
private long contentLength = 0L;
#MimeType
private String mimeType = "text/plain";
}
And to this add a "store" (the equivalent of a Repository but for content):
ImageStore.java
#StoreRestResource
public interface ImageStore extends FilesystemContentStore<Image, String> {}
This is all you need to create REST endpoints # /users/{userId}/images. When your application starts, Spring Content will look at your dependencies seeing Spring Content Filesystem, look at your ImageStore interface and inject a filesystem-based implementation of that interface. It will also see the Spring Content REST dependency and inject an #Controller implementation that forwards HTTP requests to your ImageStore. Just like Spring Data does for your UserRepository. This saves you having to implement any of this yourself which I think is what you are after.
So...
To manage content with the injected REST API:
curl -X POST /users/{userId}/images -F file=#/path/to/image.jpg
will store the image on the filesystem at `` and associate it with the user entity whose id is userId.
curl /users/{userId}/images/{contentId} -H "Accept: image/jpeg"
will fetch it again and so on...supports all CRUD methods and video streaming as well BTW!
There are a couple of getting started guides here. The reference guide for Spring Content Filesystem is here. And there is a tutorial video here. The coding bit starts about 1/2 way through.
A couple of additional points:
- if you use the Spring Boot Starters then you don't need the #Configuration for the most part.
- Just like Spring Data is an abstraction, so is Spring Content so you aren't limited to storing your images on the filesystem. You could store them as BLOBs in the database, or in cloud storage like S3.
HTH
I suggest you can use #Lob instead to save file data (fileData variable below)
#Entity
public class File {
#Id
#GeneratedValue(generator = "uuid")
#GenericGenerator(name = "uuid", strategy = "uuid2")
private String id;
private String fileName;
private String fileType;
#Lob
private byte[] fileData;
}

Ignore xml tags while serializing pojo fields to xml

I am using jackson library to map POJO to XML.
compile ('com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.9.0')
While serializing I need to ignore some of the fields. This is my POJO class. For example, the field lineNumber should be ignored.
#NoArgsConstructor
#AllArgsConstructor
#Getter
#XmlAccessorType(XmlAccessType.FIELD)
public class InvoiceLineItem {
#JacksonXmlProperty(localName = "LineNumber")
#XmlTransient
private Integer lineNumber;
#JacksonXmlProperty(localName = "ProductCode")
#XmlTransient
private String productCode;
#JacksonXmlProperty(localName = "ProductDescription")
#XmlTransient
private String productDescription;
}
I am using #XmlTransient with XmlAccessorType to ignore the fields. But the lineNumber field annotated with XmlTransient is not ignored while serializing.
Try adding the #JsonProperty(access = Access.WRITE_ONLY)
annotation to the lineNumber field.
Even thought it looks like a JSON thing,
the Jackson XmlMapper identifies the annotation and reacts accordingly.
Edit
The conclusion XmlMapper should support JSON serizlization is an example of the following, incorrect attempt at reasoning:
All men are mortal.
Socrates was mortal.
Therefore, all men are Socrates.
The XmlMapper is not a wrapper class around ObjectMapper.
It came after ObjectMapper and appears to share many features,
like the handling of some JSON annotation.

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.

Resources