How to use a DTO class passing a Embedded class for verification? - spring

How can I tackle a #Embedded class inside of a Model class?
I'm trying to use a DTO to filter and check the requests being sent to the POST mapping.
I want to check, let's say, if the fullName is not blank.
(request body below)
DentistModel.java
public class DentistModel {
#Id
#GeneratedValue(generator = "UUID")
#GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
#Column(name = "dentist_id", updatable = false, nullable = false)
#Type(type = "org.hibernate.type.UUIDCharType")
private UUID id;
#Column(nullable = false, unique = true, length = 10)
private String croNumber;
#Embedded
private Person person;
}
DentistDto.java
public class DentistDto {
#NotBlank
private String croNumber;
}
DentistController.java
#PostMapping
public ResponseEntity<Object> saveDentist(#RequestBody #Valid DentistDto dentistDto) {
if (dentistService.existsByCroNumber(dentistDto.getCroNumber())) {
return ResponseEntity.status(HttpStatus.CONFLICT).body("Conflict: CRO number is already in use.");
}
var dentistModel = new DentistModel();
BeanUtils.copyProperties(dentistDto, dentistModel);
return ResponseEntity.status(HttpStatus.CREATED).body(dentistService.save(dentistModel));
}
Dentist request body
{
"croNumber":"12345",
"person": {
"fullName": "John",
"birthDate": "2000-01-27",
"cpfNumber": "11408247910",
"telephoneNumber": "47996034002",
"emailAddress": "john#gmail.com",
"address": {
"mainAddress": "Rua Amoroso Costa",
"numberAddress": "171",
"neighborHood": "Jardim das Américas",
"complementInfo": "Casa",
"zipCode": "81530-150"
}
}
}

Related

Multipartfile charset=UTF-8 is not supported spring boot api rest

The code was working normally and I've tried in every way to solve it and I couldn't, it may be that after I transformed the MultipartFile into an array this happened
#RestController
#RequestMapping("products")
public class ProductController {
#Autowired
private ProductService productService;
#PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
#Transactional
public ResponseEntity<ShowProductsDTO> registerProduct(
#RequestBody #Valid ProductDTO dto,
#RequestParam(name = "files", required = true) MultipartFile[] files,
UriComponentsBuilder uriBuilder) {
ShowProductsDTO showProductsDTO = null;
try {
showProductsDTO = productService.save(dto, files);
} catch (IOException e) {
e.printStackTrace();
}
var uri = uriBuilder.path("/products/{id}").buildAndExpand(showProductsDTO.id()).toUri();
return ResponseEntity.created(uri).body(showProductsDTO);
}
DTO
public record ProductDTO(
#NotBlank
String name,
#NotBlank
String description,
#NotNull
#NumberFormat
BigDecimal price,
#NumberFormat
#NotNull
Integer quantity,
#NotNull
Boolean active,
#NotNull
Long sub_category_id
) {
}
Error console
Resolved [org.springframework.web.HttpMediaTypeNotSupportedException:
Content-Type
'multipart/form-data;boundary=--------------------------816548045966415708649211;charset=UTF-8'
is not supported]
Postman body > raw > json
{
"name": "Nome do produto",
"description": "descricao do produto",
"price": "2500.00",
"quantity": "2",
"active": "true",
"sub_category_id": "1"
}
Postman > body > form-data
KEY "files", TYPE file, VALUE uma imagem minha em png
Error postman
{
"timestamp": "2023-01-11T06:15:43.455+00:00",
"status": 415,
"error": "Unsupported Media Type",
"message": "Content-Type 'multipart/form-data;boundary=--------------------------056640214920648036756520;charset=UTF-8' is not supported.",
"path": "/products"
}
Product entity
#Table(name = "products")
#Entity(name = "Product")
#Getter
#Setter
#NoArgsConstructor
#EqualsAndHashCode(of = "id")
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(length = 100, unique = true, nullable = false)
private String name;
#Column(nullable = false, columnDefinition = "TEXT")
private String description;
#Column(length = 8, nullable = false, columnDefinition = "NUMERIC(8,2)")
private BigDecimal price;
#Column(nullable = false, columnDefinition = "INT")
private Integer quantity;
#Column(nullable = false, columnDefinition = "BOOLEAN")
private Boolean active;
#CollectionTable(name = "products_files",
joinColumns =
#JoinColumn(name = "product_id", referencedColumnName = "id"))
private List<String> productFiles;
#JoinColumn(name = "sub_category_id")
#ManyToOne(fetch = FetchType.EAGER)
private SubCategory subCategory;
how do I fix this error?
Change your attribute to #PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
and call your api using Postman body > raw > json.
The thing is, Content-Type: form-data handles file requests.

Why am i getting nulls in parameters inside json?

this is small spring-boot project
I am unable to get users parameteres
I still can create other users in db using POST method, but when i am trying get list of all users or only one by id, i am getting json with nulls in users parameters.
I want to get this from getUsers method
{
"id": 1,
"name": testName,
"password": testPassword,
"email": testEmail,
"phoneNumber": testPhoneNumber,
"status": USER
},
Instread of this i am getting
{
"id": null,
"name": null,
"password": null,
"email": null,
"phoneNumber": null,
"status": null
},
Here is my entity class
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id",nullable = false)
private Integer id;
#Column(name = "name",nullable = false)
private String name;
#Column(name = "password",nullable = false)
private String password;
#Column(name = "email",nullable = false)
private String email;
#Column(name = "phoneNumber",nullable = false)
private String phoneNumber;
#Column(name = "status",nullable = false)
private Status status;
}
My controller
#Controller
#RequestMapping
#RequiredArgsConstructor
#Validated
public class UserController {
private final UserService userService;
#Operation(description = "Getting list of users")
#GetMapping(
value = "/v1/users",
produces = {"application/json"}
)
public ResponseEntity<List<UserDto>> getUsers() {
return ResponseEntity.ok(userService.getUsers());
}
My service
#Service
#RequiredArgsConstructor
#Data
public class UserService {
private final UserRepository userRepository;
private final UserMapper userMapper;
public List<UserDto> getUsers() {
return StreamSupport.stream(userRepository.findAll().spliterator(), false)
.map(userMapper::userToUserDto).collect(Collectors.toList());
}

DTO and Entities mapping

I am building a Spring Rest Application, I need help with DTO's and parsing a result to a endpoint
This is json that I return at the moment to the endpoint:
{
"id": 1,
"name": "Ella - IPA Is Dead",
"description": "2015 IPA is Dead Series. Supremely floral, this hugely under-rated hop is related to Galaxy and was first cultivated in the Australian state of Victoria.",
"method": {
"mash_temp": [
{
"temp": {
"value": 65
}
}
]
}
}
I don't want to return "method" from this json, I just need "id", "name", "description", "mash_temp" - so it should look like this:
{
"id": 1,
"name": "Ella - IPA Is Dead",
"description": "2015 IPA is Dead Series. Supremely floral, this hugely under-rated hop is related to Galaxy and was first cultivated in the Australian state of Victoria. Initially given the same name as a certain Eurolager, their lawyers got involved and the St- prefix was dropped. Ella displays subtle notes of spice, but is fundamentally a truly floral bouquet, redolent of the Southern Hemisphere.",
"mash_temp": [
{
"temp": {
"value": 65
}
}
]
}
Those are the entities that I am using now:
Beer Entity:
#Entity
public class Beer implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "beer_id", unique = true, nullable = false)
private Integer id;
#Column(name = "name", nullable = false)
private String name;
#JsonProperty("description")
#Column(name = "description", nullable = false, columnDefinition = "TEXT")
private String description;
#JsonProperty("method")
#OneToOne(cascade = CascadeType.ALL)
private Method method;
}
Method Entity:
#Entity
public class Method implements Serializable
{
#JsonIgnore(value = true)
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#JsonProperty("mash_temp")
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "mash_temp")
private List<MashTemp> mash_temp = new ArrayList<>();
}
MashTemp Entity:
#Entity
public class MashTemp implements Serializable
{
#JsonIgnore(value = true)
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#OneToOne(cascade = CascadeType.ALL)
private Temp temp;
#ManyToOne
private Method method;
}
Temp Entity:
#Entity
public class Temp implements Serializable
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private Integer value;
#JsonIgnore(value = true)
private String unit;
#OneToOne
private MashTemp mashTemp;
}
Does anyone know how to create DTO's from this Entities but without "method" field?
Also this is my Controller:
#GetMapping("/beers")
public ResponseEntity<Set<Beer>> getAllBeers()
{
return new ResponseEntity<>(beerService.getAllBeers(), HttpStatus.OK);
}
#GetMapping("/beers/{id}")
public ResponseEntity<Beer> getById(#PathVariable Integer id) {
Beer beer = beerService.findById(id);
return new ResponseEntity<>(beer, HttpStatus.OK);
}
Have a look at the #JsonUnwrapped annotation (https://fasterxml.github.io/jackson-annotations/javadoc/2.8/com/fasterxml/jackson/annotation/JsonUnwrapped.html). You can put it on the method field in the Beer class, and then the properties of the Method class are serialized directly on the same level as the ones from Beer.

SnippetException: Cannot document response fields as the response body is empty

Here is my Controller:
#PostMapping("post")
#PreAuthorize("hasAuthority('WRITE')")
public ResponseEntity<?> createPost(#RequestBody PostEntity postEntity) {
return new ResponseEntity<>(postService.createPost(postEntity), HttpStatus.CREATED);
}
Service :
#Override
public Post createPost(PostEntity postEntity) {
return postFactory.buildPost(postEntityRepository.save(postEntity));
}
//Post is Immutable class here
public Post buildPost(PostEntity entity) {
return new Post.Builder()
.groupId(entity.getGroupEntity().getGroupId())
.postedBy(entity.getPostedBy().getUsername())
.postType(entity.getType())
.postMedia(entity.getPostMedia())
.postId(entity.getPostId())
.build();
}
Here is my mockMvc:
#BeforeEach
public void setUp(WebApplicationContext webApplicationContext,
RestDocumentationContextProvider restDocumentation) {
this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
.apply(documentationConfiguration(restDocumentation))
.alwaysDo(document("{method-name}",
preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint())))
.build();
}
Here is my Test:
this.mockMvc.perform(post("/api/post")
.contentType(MediaTypes.HAL_JSON)
.contextPath("/api")
.content(this.objectMapper.writeValueAsString(postEntity)))
.andExpect(status().isCreated())
.andDo(
document("{method-name}", preprocessRequest(prettyPrint()),
preprocessResponse(prettyPrint()),
requestFields(describeCreatePostRequest()),
responseFields(describePostEntityResult())
));
Here is Post call:
#Value.Immutable
#JsonSerialize(as = ImmutablePost.class)
#JsonDeserialize(as = ImmutablePost.class)
#JsonInclude(JsonInclude.Include.NON_NULL)
#Relation(value = "post", collectionRelation = "posts")
public interface Post {
Long getPostId();
String getPostType();
String postedBy();
#Nullable
PostMedia postMedia();
Long groupId();
class Builder extends ImmutablePost.Builder {}
}
PostEntity #Entity class here is json format:
{
"type" : "text",
"postedBy" : {
"username": "sandeep"
},
"postMedia" : {
"mediaType": "text",
"mediaUrl": "null",
"content": "Hi this is testing media content",
"createdAt": 1234,
"updatedAt": 689
},
"groupEntity": {
"groupId": 4
}
}
And Post entity class:
#Entity
#Table(name = "POST")
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class PostEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "POST_ID")
private Long postId;
#Column(name = "POST_TYPE")
private String type;
#ManyToOne
#JoinColumn(name = "username", referencedColumnName = "username")
private User postedBy;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "post_media_id", referencedColumnName = "id")
private PostMedia postMedia;
#ManyToOne(cascade = CascadeType.REMOVE, fetch = FetchType.LAZY)
#JoinColumn(name = "GROUP_ID", referencedColumnName = "GROUP_ID")
private GroupEntity groupEntity;
public PostEntity() {
}
}
I have tried
objectMapper.readValue(objectMapper.writeValueAsString(postEntity), ImmutablePost.class);
As well. but still its not working, I am facing same exception:
org.springframework.restdocs.snippet.SnippetException: Cannot document response fields as the response body is empty
at org.springframework.restdocs.payload.AbstractFieldsSnippet.verifyContent(AbstractFieldsSnippet.java:191)
at org.springframework.restdocs.payload.AbstractFieldsSnippet.createModel(AbstractFieldsSnippet.java:147)
at org.springframework.restdocs.snippet.TemplatedSnippet.document(TemplatedSnippet.java:78)
at org.springframework.restdocs.generate.RestDocumentationGenerator.handle(RestDocumentationGenerator.java:191)
The problem is with the "PostMedia" setters "PostMedia" and "GroupEntity". You need to accept strings in the setters parameter and convert them to the corresponding entity. Expecting the setter's arguments as the custom entity type is making the problem.
For example:
public class MyModel {
private CustomEnum myEnum;
public CustomEnum getMyEnum() {
return myEnum;
}
public void setMyEnum(String enumName) {
this.myEnum = CustomEnum.valueOf(enumName);
}
}

Add entity with OneToOne Relation using JPA and REST

I am using Spring JPA Restful, and I don't understand how to insert an entity with a foreign key.
Activity Entity:
#Entity
#Table(name= "Activity")
public class Activity implements Serializable{
#Id
#GeneratedValue(generator = "uuid")
#GenericGenerator(name="uuid", strategy = "uuid2")
#Column(name = "uuid", nullable = false, unique = true)
private UUID uuid;
#OneToOne(fetch = FetchType.EAGER, cascade=CascadeType.MERGE)
#JoinColumn(name="type", nullable = false)
private ActivityType type;
#Column(nullable = false)
private String label;
ActivityType Entity:
#Entity
#Table(name= "ActivityType")
public class ActivityType implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(nullable = false, unique = true)
private String code;
#Column(nullable = false
private String label;
Is it possible to insert Activity simply? With something like this JSON where ActivityType's id "1" exists:
createActivity:
{"label":"LABEL","type":1}
With this code I have to do:
createActivity:
{"label":"LABEL","type":{"id":1}}
which return value is:
{
"uuid": "a54b27aa-8d49-41fd-8976-70c019c40e3b",
"type": {
"id": 1,
"code": null,
"label": null
},
"label": "LABEL",
"details": null
}
I use the library gson for parsing domain classes into JSON.
//... code for making your activity, let's say you have an Activity object myActivity
Just add the following code where you want to parse your object into JSON.
Gson gson = new GSON();
String json = gson.toJson(myActivity);

Resources