I have a problem. I want to throw an exception when an attribute is null, but the #NotNull annotation doesn't seem to be working. I use Spring 2.6.4
My controller:
#RestController
public class GroupController {
#RequestMapping(value = "/journey", method = RequestMethod.POST)
public ResponseEntity<Group> create(#Valid #RequestBody GroupCreateCommand groupCreateCommand, BindingResult bindingResult) throws Exception {
Group group = groupService.create(groupCreateCommand);
journeyService.notifyNewGroup(group);
return new ResponseEntity<>(group, HttpStatus.OK);
}
}
My class:
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import javax.validation.constraints.NotNull;
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true)
public class GroupCreateCommand {
#JsonProperty("id")
#NotNull
private Long id;
#JsonProperty("people")
#NotNull
private Integer people;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Integer getPeople() {
return people;
}
public void setPeople(Integer people) {
this.people = people;
}
}
Request:
curl --location --request POST 'http://localhost:8080/journey' \
--header 'Content-Type: application/json' \
--data-raw '{
"id": 3
}'
Result:
As you can see, the exception is not thrown, but the seats attribute is mapped as null.
pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
Thanks!
Here you are expecting validation result in BindingResult parameter.This parameter helps you in case you want some special handling for validation failures.
you can remove BindingResult parameter from controller method or you can add below code snippet in controller method to view validation error for request body
if(bindingResult.hasErrors()){
bindingResult.getFieldErrors().stream().forEach(error -> {
System.out.println(error.getField() + ":" + error.getDefaultMessage());
});
}
Related
i'm trying to save entity in cosmos db through spring boot micro service. I'm not getting any error, only 1 warning '[osEventLoop-6-1] c.a.d.c.i.d.rntbd.RntbdRequestManager : ChannelHandlerContext(RntbdRequestManager#0, [id: 0x999bfbac, L:0.0.0.0/0.0.0.0:56979 ! R:cdb-ms-prod-*****-****.documents.azure.com/********]) channelUnregistered exceptionally'
but data is not getting saved in cosmos db. i'm using reactivecosmosrepository.
here is my pom.xml
<properties>
<java.version>1.8</java.version>
<azure.version>2.2.0</azure.version>
</properties>
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-cosmosdb-spring-boot-starter</artifactId>
<version>${azure.version}</version>
</dependency>
my entity
import com.microsoft.azure.spring.data.cosmosdb.core.mapping.Document;
#Document(collection = "dashboardsnapshot")
public class DashboardSnapshot {
private String id;
private String clientId;
private String snapshotJSON;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getClientId() {
return clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public String getSnapshotJSON() {
return snapshotJSON;
}
public void setSnapshotJSON(String snapshotJSON) {
this.snapshotJSON = snapshotJSON;
}
#Override
public String toString() {
return "DashboardSnapshot [id=" + id + ", clientId=" + clientId + ", snapshotJSON=" + snapshotJSON + "]";
}
}
my repository
import org.springframework.stereotype.Repository;
import com.ka.concept.dashboardconfig.entity.DashboardSnapshot;
import com.microsoft.azure.spring.data.cosmosdb.repository.ReactiveCosmosRepository;
import reactor.core.publisher.Flux;
#Repository
public interface SnapshotDao extends ReactiveCosmosRepository<DashboardSnapshot, String>{
Flux<DashboardSnapshot> findbyClientId(String ClientId);
}
my service
#Service
public class SnapshotServiceImpl implements SnapshotService{
#Autowired
public SnapshotDao snapshotdao;
#Override
public boolean saveSnapshotConfig(DashboardSnapshot snapshotJSON) {
// TODO Auto-generated method stub
snapshotdao.save(snapshotJSON);
return true;
}
}
#AksYou should call subscribe(). The publisher does not do anything till some one subscribes.
snapshotdao.save(snapshotJSON).subscribe();
I'm working on a service which accepts a DTO in a POST method and creates an entity based on that DTO. Nested inside is a multipart file, which is going to be an image used by the entity that will be created.
Using postman to test my backend, I keep receiving an seemingly empty DTO. The three logs inside the controller return null, 0 and null respectively.
This is how I setup my data, which I am quite sure is the problem:
I converted my image into a base64 string, which as far as I know is the only way I can post a nested image.
Code
Controller
#PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<InventoryComponentDto> create(#ModelAttributee InventoryComponentDto request) {
System.out.println(request.getDescription());
System.out.println(request.getMinimal_supply());
System.out.println(request.getComponent());
InventoryComponentDto result = inventoryComponentService.create(request);
if (result == null) {
return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST);
}
return ResponseEntity.ok(result);
}
InventoryComponentDto
public class InventoryComponentDto {
private ComponentDto component;
private String description;
private Date createdAt;
private Date updatedAt;
private int minimal_supply;
private int supply;
}
ComponentDto
public class ComponentDto {
private Long id;
private int number;
private String name;
private FileDto image;
}
FileDto
public class FileDto {
private String name;
private String type;
private String url;
private MultipartFile data;
}
What would be the way for me to adequately create my dto in postman, including an image?
Update
"status": 400,
"error": "Bad Request",
"message": "JSON parse error: (was java.lang.NullPointerException); nested exception is com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: com.package.MCI.dto.InventoryComponentDto[\"component\"]->com.package.MCI.dto.ComponentDto[\"image\"])",
"trace": "org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: (was java.lang.NullPointerException); nested...
You need to create a custom jackson deserializer.
//CustomDeserializer
import java.io.IOException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItem;
import org.springframework.util.Base64Utils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
public class CustomDeserializer extends StdDeserializer<FileDTO> {
public CustomDeserializer() {
super(FileDTO.class);
}
protected CustomDeserializer(Class<?> vc) {
super(vc);
}
#Override
public FileDTO deserialize(JsonParser jsonParser,
DeserializationContext deserializationContext)
throws IOException, JsonProcessingException {
JsonNode node = jsonParser.getCodec().readTree(jsonParser);
String name = node.get("name").asText();
String url = node.get("url").asText();
String type = "." + node.get("type").asText();
String fileBase64 = node.get("data").asText();
byte[] fileBytes = Base64Utils.decodeFromString(fileBase64);
FileItem fileItem = new DiskFileItem(name, "image/jpg", false, name + type,
fileBytes.length, null);
fileItem.getOutputStream().write(fileBytes);
fileItem.getOutputStream().flush();
MultipartFile file = new CommonsMultipartFile(fileItem);
fileItem.getOutputStream().close();
FileDTO fileDTO = new FileDTO();
fileDTO.setName(name);
fileDTO.setUrl(url);
fileDTO.setType(type);
fileDTO.setData(file);
return fileDTO;
}
}
And use it like:
//FileDTO
#JsonDeserialize(using = CustomDeserializer.class)
public class FileDTO {
You need these two dependencies:
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
Executing orderRequestDao.save(new OrderRequest("5000", "body")); successfully places a record in Dynamo. Any attempts to read returns:
[Request processing failed; nested exception is com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMappingException:
could not invoke null on class
com.cfa.fulfillmentApi.model.OrderRequest
with value 100 of type class java.lang.String] with root cause
(Record with id: 100 exists)
I'm using the following jars (aws.sdk.version: 1.11.86):
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk</artifactId>
<version>${aws.sdk.version}</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-core</artifactId>
<version>${aws.sdk.version}</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-dynamodb</artifactId>
<version>${aws.sdk.version}</version>
</dependency>
<dependency>
<groupId>com.github.derjust</groupId>
<artifactId>spring-data-dynamodb</artifactId>
<version>4.4.1</version>
</dependency>
DyamoDb config:
Primary partition key: id (String)
Dao:
#EnableScan
public interface OrderRequestDao extends CrudRepository<OrderRequest, String> {
OrderRequest findOne(String s);
OrderRequest save(OrderRequest or);
}
Domain object:
#DynamoDBTable(tableName = "dev_transx")
public class OrderRequest {
private String id;
private String body;
public OrderRequest(String id, String body) {
this.id = id;
this.body = body;
}
public OrderRequest() {}
#DynamoDBHashKey
public String getId()
{
return id;
}
#DynamoDBAttribute
public String getBody()
{
return body;
}
public void setBody(String body) {
this.body = body;
}
#Override
public String toString() {
return String.format(
"Customer[id=%d, body='%s']",
id, body);
}
#Override
public int hashCode() {
return id.hashCode();
}
}
I've tried just about every data type for id in the domain class, but no luck.
I removed aws-java-sdk-dynamodb since it was already in spring-data-dynamodb
Most importantly I added a setter for ID in the domain class.
Adding a setter method for the field works like a charm
I have an implementation of a REST front-end UI and a Spring JPA based backend.
In it, I have a class like this:
public class TaskInfo {
// 4 fields
private Parent parentList;
// 3 fields
// Getters and Setters
}
class Parent {
// Parent class code
}
When I try to take a Response, I find that in place of Parent, I get a null value. Why is this Parent object not getting serialized? Is there a workaround to this? Or should I just include the fields of Parent in this class directly?
Edit: I'm using Jackson for serialization.
For me the below works fine. I think this is equivalent to the code present in your question
package jackson;
import java.io.IOException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class TaskInfo {
public TaskInfo(String id, Parent parentList) {
super();
this.id = id;
this.parentList = parentList;
}
private String id;
private Parent parentList;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Parent getParentList() {
return parentList;
}
public void setParentList(Parent parentList) {
this.parentList = parentList;
}
public static void main(String args[]) throws IOException {
Parent parent = new Parent("123");
TaskInfo taskInfo = new TaskInfo("taskID", parent);
String json = new ObjectMapper().writeValueAsString(taskInfo);
System.out.println(json);
}
}
class Parent {
public Parent(String parentId) {
this.parentId = parentId;
}
public String getParentId() {
return parentId;
}
public void setParentId(String parentId) {
this.parentId = parentId;
}
private String parentId;
// Parent class code
}
It prints the following output
{"id":"taskID","parentList":{"parentId":"123"}}
I used jackson
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.7.1</version>
</dependency>
It doesn't serialize because your properties are not public. Make the properties public and it works.
What are the maven dependencies need to be added to get the XML output without configuring content negotiation view resolver and managers. By using the default Message Converters based on jars on classpath (output based on accept headers). I am able to get the JSON output by having jackson-databind dependency on the classpath. For XML I am using
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.2.7</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.2.7</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${org.springframework.version}</version>
</dependency>
dependencies - I am unable to get the XML output. DO I need configure any Marshallers like Jaxb2Marsahllar as a bean in the configuration file. Can Any post the maven dependencies for JAXB2.
My Entity class:
package com.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import org.hibernate.validator.constraints.NotEmpty;
#Entity
#Table(name = "Employee")
#XmlRootElement
public class Employee {
public Employee() {
}
public Employee(Integer empno, String name, String dept, Double salary) {
this.empno = empno;
this.name = name;
this.dept = dept;
this.salary = salary;
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer empno;
#Size(min = 1, max = 30)
#NotEmpty
private String name;
#NotEmpty
#Size(min = 1, max = 30)
private String dept;
/*
* #NotEmpty - cannot be set to double - supports String Collection Map
* arrays
*/
private Double salary;
#XmlAttribute
public Integer getEmpno() {
return empno;
}
public void setEmpno(Integer empno) {
this.empno = empno;
}
#XmlElement
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#XmlElement
public String getDept() {
return dept;
}
public void setDept(String dept) {
this.dept = dept;
}
#XmlElement
public Double getSalary() {
return salary;
}
public void setSalary(Double salary) {
this.salary = salary;
}
#Override
public String toString() {
return "Employee [empno=" + empno + ", name=" + name + ", dept=" + dept
+ ", salary=" + salary + "]";
}
}
My Controller Class:
#Controller
public class EmployeeController {
#Autowired
EmployeeRepository employeeRepository;
#RequestMapping(value = "/employees", method=RequestMethod.GET,
produces= {MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE})
public #ResponseBody List<Employee> findAllXml(){
return employeeRepository.findAll();
}
}
Please Can any one say Whether the dependencies are enough ? What needs to be added..
put #XMLElement on set methods.
public Integer getEmpno() {
return empno;
}
#XmlAttribute
public void setEmpno(Integer empno) {
this.empno = empno;
}
public String getName() {
return name;
}
#XmlElement
public void setName(String name) {
this.name = name;
}
or you can use Spring Marshalling View of spring-oxm.jar
<bean id="xmlViewer"
class="org.springframework.web.servlet.view.xml.MarshallingView">
<constructor-arg>
<bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>com.model.Employee</value>
</list>
</property>
</bean>
</constructor-arg>
</bean>
Update:1
Also findAll is returning list that list needs to be accomodated in a parent tag like
<Employees>
<Employee />
<Employee />
</Employees>
so you need to define a class that has an #XMLElement entity as List<Employees> create object of it put the data in it and return that object.
I found the answer to 406 exception
Problem was needed an extra configuration for Message Converters for XML output.
For XML Output, we need to Added a Message Converter to the list of Message converters of RequestMappingHandlerAdapter
But for JSON we dont need to do this explictly, based on the jackson-databind dependencies on the classpath, we can able get the JSON output. But for xml , we need to add a message converter (MarshallingHttpMessageConverter) .
Example: Using Java Based Config: configuring RequestMappingHandlerAdapter as a bean and adding required Message Converters...
#Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
RequestMappingHandlerAdapter adapter = new RequestMappingHandlerAdapter();
List<HttpMessageConverter<?>> converters = new ArrayList();
converters.add(new MarshallingHttpMessageConverter(
new XStreamMarshaller()));
converters.add(new MappingJackson2HttpMessageConverter());
adapter.setMessageConverters(converters);
return adapter;
}
I am using XStream Marshaller, so need to add its dependencies as well
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.8</version>
</dependency>
Example Tests:
#Test
public void testXml() throws Exception {
this.mvc.perform(get("/employees/xml").accept(APPLICATION_XML))
.andDo(print())
.andExpect(content().contentType("application/xml"));
}
#Test
public void testJson() throws Exception {
this.mvc.perform(get("/employees/json").accept(APPLICATION_JSON))
.andDo(print())
.andExpect(content().contentType("application/json"));
}
Please post if you know any other way of doing this.
useful link: Spring XML 406 error