I am trying to build a system where the frontend and backend are separated and interact through rest calls with authorization based on user token. Both the frontend and backend applications are built on Springboot. Thymeleaf is used as template engine for rendering html pages.
I am trying to upload a file for a user, which I will try to save in filesystem of my backend server. The problem I am encountering is that the file I upload on the browser is not getting serialised, either as byte[] (when I try to send octet-stream as content-type) or as json (when I try to send json as content-type).
The relevant html for this issue is :
<form id="doctorDetailsId" enctype="multipart/form-data">
<input name="firstName" placeholder="first name"/>
Profile pic: <input name="photo" type="file"/>
<input name="username" placeholder="user name"/>
<input name="password" placeholder="password"/>
<button type="submit">Submit</button>
</form>
On clicking the submit button, the following js code sends ajax call with parameters to the frontend server.
$("#doctorDetailsId").ajaxForm({
url: '/doctor/add',
type: 'post',
processData: false,
success: function (data) {
console.log("Added Doctor! data = " + JSON.stringify(data))
}
})
Ajax request is sent fine, and the controller in the frontend application receives the request.
@RequestMapping(value = URLConstants.DOCTOR + "/add", method = RequestMethod.POST)
@ResponseBody
public Map<String, Object> addDoctor(MultipartHttpServletRequest request, HttpServletResponse response) throws Exception {
String token = (String) request.getSession().getAttribute("token");
String role = (String) request.getSession().getAttribute("userRole");
if (token != null && !token.isEmpty()) {
if (role.equals(UserRole.ADMIN.getDescription())) {
String username = request.getParameter("username");
String password = request.getParameter("password");
String firstName = request.getParameter("firstName");
MultipartFile multipartFile1 = request.getFile("photo");
// Part file = request.getPart("photo");
DoctorCO doctorCO = new DoctorCO(firstName, multipartFile1);
.
.
.
String url = backendServerUrl + ":" + backendServerPort + BackApis.ADD_DOCTOR;
//RequestResponseDTO requestResponseDTO = HttpUtils.postData(url,
token, RequestMethod.POST.toString(), doctorCO);
RequestResponseDTO requestResponseDTO = HttpUtils.postDataWithoutJsonSerialising(url,
token, RequestMethod.POST.toString(), doctorCO);
DoctorDto doctorDto = objectMapper.convertValue(requestResponseDTO.getData(), DoctorDto.class);
.
.
return doctorDto;
} else {
return null;
}
}
return null;
}
The httpUtils.postData() method does jackson serialization, while the other one gets byte array of the object passed.
public String toJson(Object o) {
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
if (o == null) {
return null;
}
try {
return mapper.writeValueAsString(o);
} catch (Exception e) {
logger.error(JacksonUtils.class.getSimpleName(), e);
throw new RuntimeException(e);
}
}
public static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(out);
os.writeObject(obj);
return out.toByteArray();
}
When the DoctorCO object comes for serialization, none of the methods are able to serialize the MultipartFile object.
This exception comes when I try to use the serialize method.
java.io.NotSerializableException: org.apache.catalina.core.ApplicationPart
The other exception when I try to use the toJson method is related to stackOverflow error (infinite recursion)
*** java.lang.instrument ASSERTION FAILED ***: "!errorOutstanding" with message transform method call failed at JPLISAgent.c line: 844
*** java.lang.instrument ASSERTION FAILED ***: "!errorOutstanding" with message transform method call failed at JPLISAgent.c line: 844
*** java.lang.instrument ASSERTION FAILED ***: "!errorOutstanding" with message transform method call failed at JPLISAgent.c line: 844
*** java.lang.instrument ASSERTION FAILED ***: "!errorOutstanding" with message transform method call failed at JPLISAgent.c line: 844
2016-12-21 20:23:11.493 ERROR 25797 --- [nio-8082-exec-1] com.src.main.utils.JacksonUtils : JacksonUtils
com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]-.....>java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"]->java.io.FileOutputStream["fd"]->java.io.FileDescriptor["parent"])
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:706) ~[jackson-databind-2.8.1.jar:2.8.1]
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155) ~[jackson-databind-2.8.1.jar:2.8.1]
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:693) ~[jackson-databind-2.8.1.jar:2.8.1]
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:690) ~[jackson-databind-2.8.1.jar:2.8.1]
.
.
.
.
I have been stuck in finding a solution to serialize the file from frontend to backend server for quite long. Please let me know what's going wrong here, or if someone has a better solution for uploading a file in this manner, please let me know. I will be happy to provide any more details if required.