How to send headers from controller into another class in Java - java

I have a controller like below
SubmitBatchController.java
#RestController
#RequestMapping({"/"})
#Api(value = "batch", tags = {"Batch "}, authorizations = {#Authorization(value="JwtToken")})
public class SubmitBatchController extends BasicController {
#PostMapping(value = "v1/batch", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public CommonResponse<BatchSubmissionResponseModel> submitBatchClaim(
#ApiParam(hidden = true) #RequestHeader(required = false) String transId,
#ApiParam(hidden = true) #RequestHeader(required = false) String paymentReleaseInd,
#ApiParam(hidden = true) #RequestHeader(required = false) String emailMatchedInd,
#ApiParam(hidden = true) #RequestHeader(vrequired = false) String role,
#RequestBody BatchSubmissionRequestModel batchSubmissionRequestModel,
BindingResult br, HttpServletRequest request, HttpServletResponse response) throws Exception {
LocalDateTime startLocaleDateTime = LocalDateTime.now();
BatchSubmissionResponseModel batchSubmissionResponseModel = new BatchSubmissionResponseModel();
ContextBase ctxBase = getChainBaseContext(request);
ctxBase.put(PARAM_LOC.RESPONSE, batchSubmissionResponseModel);
HeaderRequestModel headers = new headerRequestModel();
batchSubmissionRequestModel.setTransId(transId);
headers.setRole(role);
headers.setPaymentReleaseInd(paymentReleaseInd);
headers.setEmailMatchedInd(emailMatchedInd);
batchSubmissionRequestModel.setHeaderRequestModel(headers);
}
}
BatchSubmissionRequestModel.java
public class BatchSubmissionRequestModel {
#ApiModelProperty(hidden = true) // this is captured as a header and set in the controller
#NotBlank(message = "Headers.transId.NotBlank")
private String transId;
#ApiModelProperty(hidden = true)
private HeaderRequestModel headerRequestModel;
public String getTransId() {
return transId;
}
public void setTransId(String transId) {
this.transId = transId;
}
public HeaderRequestModel getHeaderRequestModel() {
return headerRequestModel;
}
public void setHeaderRequestModel(HeaderRequestModel headerRequestModel) {
this.headerRequestModel= headerRequestModel;
}
}
HeaderRequestModel.java
public class HeaderRequestModel {
private String paymentReleaseInd;
private String emailMatchedInd;
private String role;
public String getPaymentReleaseInd() {
return paymentReleaseInd;
}
public void setPaymentReleaseInd(String paymentReleaseInd) {
this.paymentReleaseInd = paymentReleaseInd;
}
public String getEmailMatchedInd() {
return emailMatchedInd;
}
public void setEmailMatchedInd(String emailMatchedInd) {
this.emailMatchedInd = emailMatchedInd;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
}
Now I have another class, which has to take the headers from SubmitBatchController.java & set it into FullEligibilityService.java
FullEligibilityRequestModel.java
public class FullEligibilityRequestModel{
private String transId;
private HeaderRequestModel headerRequestModel;
public String getTransId() {
return transId;
}
public void setTransId(String transId) {
this.transId = transId;
}
public DapHeaderRequestModel getDapHeaderRequestModel() {
return dapHeaderRequestModel;
}
public void setDapHeaderRequestModel(DapHeaderRequestModel dapHeaderRequestModel) {
this.dapHeaderRequestModel = dapHeaderRequestModel;
}
}
FullEligibilityService.java
(request is mapped to FullEligibilityRequestModel)
#Service
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class FullEligibilityServiceextends extends AServiceTask <FullEligibilityRequestModel, FullEligibilityResponseModel>{
private static final String HEADER_FULL_ELIGIBILITY_TRANS_ID = "transId";
private static final String HEADER_PAYMENT_RELEASE_INDICAATOR = "paymentReleaseInd";
private static final String HEADER_EMAIL_MATCHED_INDICATOR = "emailMatchedInd";
private static final String HEADER_ROLE = "role";
#Override
protected void processTask() {
try {
Map<String, String> headers = new HashMap<String, String>();
headers.put(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
headers.put(HEADER_FULL_ELIGIBILITY_TRANS_ID, request.getTransId());
headers.put(HEADER_PAYMENT_RELEASE_INDICAATOR, request.getHeaderRequestModel().getPaymentReleaseInd()); // getting NULL
headers.put(HEADER_EMAIL_MATCHED_INDICATOR, request.getHeaderRequestModel().getEmailMatchedInd()); // getting NULL
headers.put(HEADER_DAP_ROLE, request.getHeaderRequestModel().getRole()); // getting NULL
.....
}
catch (Exception e) {
LOGGER.error("FullEligibilityService.processTask call failed");
exception = e;
status = STATUS_TASK_EXCEPTION;
e.printStackTrace();
}
}
I'm not able to get the headers set in SubmitBatchController.java into FullEligibilityService.java, due to which I get null values.
Can someone help me how to set the PaymentReleaseInd, EmailMatchedInd, HeaderRequestModel set in SubmitBatchController.java into FullEligibilityService.java

You need to inject an instance of FullEligibilityService into SubmitBatchController as follows and then you just need to call the corresponding method with the required parameters:
#RestController
#RequestMapping({"/"})
#Api(value = "batch", tags = {"Batch "}, authorizations = {#Authorization(value="JwtToken")})
public class SubmitBatchController extends BasicController {
#Autowired
FullEligibilityService fullEligibilityService;
#PostMapping(value = "v1/batch", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public CommonResponse<BatchSubmissionResponseModel> submitBatchClaim(
#ApiParam(hidden = true) #RequestHeader(required = false) String transId,
#ApiParam(hidden = true) #RequestHeader(required = false) String paymentReleaseInd,
#ApiParam(hidden = true) #RequestHeader(required = false) String emailMatchedInd,
#ApiParam(hidden = true) #RequestHeader(vrequired = false) String role,
#RequestBody BatchSubmissionRequestModel batchSubmissionRequestModel,
BindingResult br, HttpServletRequest request, HttpServletResponse response) throws Exception {
LocalDateTime startLocaleDateTime = LocalDateTime.now();
BatchSubmissionResponseModel batchSubmissionResponseModel = new BatchSubmissionResponseModel();
ContextBase ctxBase = getChainBaseContext(request);
ctxBase.put(PARAM_LOC.RESPONSE, batchSubmissionResponseModel);
HeaderRequestModel headers = new headerRequestModel();
batchSubmissionRequestModel.setTransId(transId);
headers.setRole(role);
headers.setPaymentReleaseInd(paymentReleaseInd);
headers.setEmailMatchedInd(emailMatchedInd);
fullEligibilityService.processTask(paymentReleaseInd, emailMatchedInd, headers);
}
(...)
}
You need to change Service to accept the data you need as follows:
#Service
public class FullEligibilityServiceextends extends AServiceTask <FullEligibilityRequestModel, FullEligibilityResponseModel>{
public void processTask(String paymentReleaseInd, String emailMatchedInd, HeaderRequestModel headers) {
(...) //Whatever logic you want to implement
}
Right now you are trying to pass around the data you need via request headers which is definitely a bad practice.

Related

thenReturn() wants Optional, but test fails

I'm trying to do an Unit test, but I receive the error 'cannot resolve the method thenReturn(suspectTest) ; wrap using java.Optional', but when I do (.thenReturn(Optional.of(suspectTest)), the test fails - 'Optional cannot be cast to class Suspect'. Here it is the test, the SuspectService and the SuspectController (edited post*). Thank you in advance!
#DataJpaTest
public class ControllerTest {
#Mock
Model model;
#Mock
SuspectService suspectService;
SuspectController suspectController;
#Rule
public MockitoRule rule = MockitoJUnit.rule();
#Before
public void setUp() throws Exception {
suspectController = new SuspectController(suspectService);
}
#Captor
ArgumentCaptor<Suspect> argumentCaptor;
#Test
public void showById() {
Integer id = 1;
Suspect suspectTest = new Suspect();
suspectTest.setId(Long.valueOf(id));
when(suspectService.getById(Long.valueOf(id))).thenReturn(Optional.of(suspectTest));
String viewName = suspectController.showById(id.toString(), model);
Assert.assertEquals("info", viewName);
verify(suspectService, times(1)).getById(Long.valueOf(id));
verify(model, times(1))
.addAttribute(eq("suspect"), argumentCaptor.capture() );
Suspect suspectArg = argumentCaptor.getValue();
Assert.assertEquals(suspectArg.getId(), suspectTest.getId() );
}
}
#Service
public class SuspectService implements BaseService<Suspect> {
private final com.unibuc.AWBD_Project_v1.repositories.SuspectRepository suspectRepository;
#Autowired
public SuspectService(SuspectRepository SuspectRepository) {
this.suspectRepository = SuspectRepository;
}
#Override
public Suspect insert(Suspect object) {
return suspectRepository.save(object);
}
#Override
public Suspect update(Long id, Suspect updatedObject) {
var foundId = suspectRepository.findById(id);
return foundId.map(suspectRepository::save).orElse(null);
}
#Override
public List<Suspect> getAll() {
return suspectRepository.findAll();
}
#Override
public Optional<Suspect> getById(Long id) {
return suspectRepository.findById(id);
}
#Override
public void deleteById(Long id)
{
try {
suspectRepository.deleteById(id);
} catch (SuspectException e) {
throw new SuspectException("Suspect not found");
}
}
#Override
public Page<Suspect> findAll(int page, int size, String sortBy, String sortType){
Sort sort = sortType.equalsIgnoreCase(Sort.Direction.ASC.name()) ? Sort.by(sortBy).ascending() :
Sort.by(sortBy).descending();
Pageable pageable = PageRequest.of(page - 1, size, sort);
return suspectRepository.findAll(pageable);
}
}
#RestController
#RequestMapping("/api/suspect")
public class SuspectController implements BaseController<Suspect> {
private final com.unibuc.AWBD_Project_v1.services.SuspectService SuspectService;
#Autowired
public SuspectController(SuspectService SuspectService) {
this.SuspectService = SuspectService;
}
#PostMapping("/suspects/add")
#Override
public String NewObject(Model model) {
model.addAttribute("suspect", new Suspect());
return "addsuspect";
}
#PostMapping("/suspects/update/{id}")
#Override
public String update(#PathVariable Long id, #Valid #ModelAttribute("suspect") Suspect suspect, BindingResult bindingResult, Model model) {
if(bindingResult.hasErrors())
{
boolean update = true;
model.addAttribute("update", update);
return "addsuspect";
}
SuspectService.insert(suspect);
return "redirect:/suspects";
}
#DeleteMapping("/suspects/delete/{id}")
#Override
public String deleteById(#PathVariable Long id) {
try {
SuspectService.deleteById(id);
} catch (SuspectException e)
{
throw new SuspectException("Suspect with " + id + " does not exist!");
}
return "redirect:/suspects";
}
#GetMapping("/suspect/{id}")
public String showById(#PathVariable String id, Model model){
model.addAttribute("suspect",
SuspectService.getById(Long.valueOf(id)));
return "info";
}
#RequestMapping("/suspects")
public String objectsList(#RequestParam(value = "page", required = false) Integer page,
#RequestParam(value = "sortBy", required = false) String sortBy,
#RequestParam(value = "sortType", required = false) String sortType, Model model) {
int size = 5;
if (page == null)
page = 1;
if(sortBy==null)
sortBy ="name";
if(sortType==null)
sortType ="asc";
Page<Suspect> pageSuspect = SuspectService.findAll(page, size, sortBy, sortType);
List<Suspect> suspects = pageSuspect.getContent();
model.addAttribute("currentPage", page);
model.addAttribute("totalPages", pageSuspect.getTotalPages());
model.addAttribute("totalItems", pageSuspect.getTotalElements());
model.addAttribute("sortBy", sortBy);
model.addAttribute("sortType", sortType);
model.addAttribute("reverseSortDir", sortType.equals("asc") ? "desc" : "asc");
model.addAttribute("suspects", suspects);
var suspect = new Suspect();
model.addAttribute("suspect", suspect);
return "suspects";
}
}

Spring rest controller not working for file upload

I have tried a rest api without any View with mongodb. My application is working fine with Spring boot embedded server with no error. With standalone tomcat application is running without error but cannot access #RestController mapped url. It shows 404 page not found. It is not creating that url but other url works fine.
Here is config
FileStorageProperties.java
#Component
public class FileStorageProperties {
private static String baseDir = "E://temp//FileManager//";
private String uploadDir = "";
public String getUploadDir() {
return baseDir + uploadDir;
}
public void setUploadDir(String uploadDir) {
this.uploadDir = baseDir + uploadDir;
}
}
MediaTypeUtils.java
public class MediaTypeUtils {
// abc.zip
// abc.pdf,..
public static MediaType getMediaTypeForFileName(ServletContext servletContext, String fileName) {
// application/pdf
// application/xml
// image/gif, ...
String mineType = servletContext.getMimeType(fileName);
try {
MediaType mediaType = MediaType.parseMediaType(mineType);
return mediaType;
} catch (Exception e) {
return MediaType.APPLICATION_OCTET_STREAM;
}
}
}
Here is model
Avatar.java:
#Document
#Component
public class Avatar {
#Id
// #Indexed(unique = true)
private String id;
private String originalName;
#Indexed(unique = true)
private String generatedName;
private String size;
#DBRef
private User user;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getOriginalName() {
return originalName;
}
public void setOriginalName(String originalName) {
this.originalName = originalName;
}
public String getGeneratedName() {
return generatedName;
}
public void setGeneratedName(String generatedName) {
this.generatedName = generatedName;
}
public String getSize() {
return size;
}
public void setSize(String size) {
this.size = size;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
#Override
public String toString() {
return "Avatar [id=" + id + ", originalName=" + originalName + ", generatedName=" + generatedName + ", size="
+ size + ", user=" + user + "]";
}
}
UploadFileResponse.java
public class UploadFileResponse {
private String fileName;
private String fileType;
private long size;
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String getFileType() {
return fileType;
}
public void setFileType(String fileType) {
this.fileType = fileType;
}
public long getSize() {
return size;
}
public void setSize(long size) {
this.size = size;
}
public UploadFileResponse(String fileName, String fileType, long size) {
this.fileName = fileName;
this.fileType = fileType;
this.size = size;
}
}
FileStorageException.java
public class FileStorageException extends RuntimeException {
/**
*
*/
private static final long serialVersionUID = -2482390550398268830L;
public FileStorageException(String message) {
super(message);
}
public FileStorageException(String message, Throwable cause) {
super(message, cause);
}
}
MyFileNotFoundException.java
#ResponseStatus(HttpStatus.NOT_FOUND)
public class MyFileNotFoundException extends RuntimeException {
/**
*
*/
private static final long serialVersionUID = -7680896574598153059L;
public MyFileNotFoundException(String message) {
super(message);
}
public MyFileNotFoundException(String message, Throwable cause) {
super(message, cause);
}
}
Now repository:
AvatarRepository.java
public interface AvatarRepository extends MongoRepository<Avatar, String>{
public Avatar findAvatarByGeneratedName(String generatedName);
public Avatar findAvatarByUser(User user);
}
AvatarRepositopryImpl.java - There are some overrided MongoRepository methods which are ignored on the following code as those are not used at all.
#Repository
public class AvatarRepositopryImpl implements AvatarRepository {
#Autowired
MongoTemplate mongoTemplate;
private static final String COLLECTION_NAME = "avatar";
#Override
public <S extends Avatar> List<S> saveAll(Iterable<S> entities) {
// TODO Auto-generated method stub
return null;
}
#Override
public List<Avatar> findAll() {
return mongoTemplate.findAll(Avatar.class, COLLECTION_NAME);
}
#Override
public <S extends Avatar> S save(S entity) {
return mongoTemplate.save(entity);
}
#Override
public void deleteById(String id) {
mongoTemplate.remove(id);
}
#Override
public void delete(Avatar entity) {
mongoTemplate.remove(entity);
}
#Override
public Avatar findAvatarByGeneratedName(String generatedName) {
Query query = new Query();
query.addCriteria(Criteria.where("generatedName").is(generatedName));
return (Avatar) mongoTemplate.findOne(query, Avatar.class);
}
#Override
public Avatar findAvatarByUser(User user) {
// System.out.println(user);
Query query = new Query();
query.addCriteria(Criteria.where("user").is(user));
return (Avatar) mongoTemplate.find(query, Avatar.class);
}
}
Here is my service:
AvatarService.java
#Service
public class AvatarService {
#Autowired
private Avatar avatar;
//
// #Autowired
// private FileStorageService fileStorageService;
#Autowired
AvatarRepository avatarRepository;
/**
* #param fileStorageService
* #param avatarRepository
*/
public Avatar findAvatarByGeneratedName(String generatedName) {
return avatarRepository.findAvatarByGeneratedName(generatedName);
}
public Avatar findAvatarByUser(User user) {
System.out.println(user);
return avatarRepository.findAvatarByUser(user);
}
public Avatar saveAvatar(User user,String fileOriginalName, String fileNameToSave, String fileSize) {
avatar.setId(UUID.randomUUID().toString());
avatar.setOriginalName(fileOriginalName);
avatar.setGeneratedName(fileNameToSave);
avatar.setSize(fileSize);
avatar.setUser(user);
return avatarRepository.save(avatar);
}
public void deleteAvatarByGeneratedName(String generatedName, Avatar avatar) {
avatar = findAvatarByGeneratedName(generatedName);
avatarRepository.deleteById(avatar.getId());
}
AvatarManager.java
public class AvatarManager {
AvatarService avatarService;
#Autowired
Avatar avatar;
public AvatarManager(AvatarService avatarService) {
this.avatarService = avatarService;
}
public String saveAvatar(User user, MultipartFile file) {
deleteAvatarByUser(user);
String[] ext = file.getOriginalFilename().split(Pattern.quote("."));
String generatedName = new UUIDGenerator().generateId(avatar).toString() + "." + ext[ext.length - 1];
avatarService.saveAvatar(user, file.getOriginalFilename(), generatedName, file.getSize() + "");
new FileStorageService(new FileStorageProperties()).uploadFile(file, generatedName);
new UploadFileResponse(generatedName, file.getContentType(), file.getSize());
return generatedName;
}
public void deleteAvatar(String generatedName) {
Avatar avatar = avatarService.findAvatarByGeneratedName(generatedName);
if (avatar != null) {
new FileStorageService(new FileStorageProperties()).deleteFile(generatedName);
avatarService.deleteAvatarByGeneratedName(generatedName, avatar);
}
}
public void deleteAvatarByUser(User user) {
// System.out.println(user);
avatar = avatarService.findAvatarByUser(user);
// System.out.println(avatar.getGeneratedName());
if (avatar != null) {
deleteAvatar(avatar.getGeneratedName());
}
}
public ResponseEntity<Resource> downloadAvatar(String avatarGeneratedName, HttpServletRequest request) {
// System.out.println(request);
return new FileStorageService(new FileStorageProperties()).downloadFile(avatarGeneratedName, request);
}
}
Now Controller. I am giving two mapping. The first one is not involved with file manager. It works on both server. The another one is working on spring boot embedded server but not on standalone tomcat. It also is not showing any error or create any url.
Here is the Controller.java;
#CrossOrigin(origins = { "*" })
#RestController
public class UserController {
#Autowired
EmployeeService employeeService;
#Autowired
UserService userService;
#Autowired
AvatarService avatarService;
#Autowired
BCryptPasswordEncoder passwordEncoder;
//It works on both server
#RequestMapping(value = "/login", method = RequestMethod.POST)
public String loginEmployee(#RequestParam Map<String, String> data) {
return new EmployeeManager(employeeService, userService)
.validateUserLogin(data.get("0").toString(), data.get("1"), passwordEncoder).toString();
}
//It doesn't work with standalone server
#RequestMapping(value = "/edit-employee-profile", method = RequestMethod.POST)
public void editProfileEmployee(#RequestParam(value = "avatar", required = false) MultipartFile file,
#RequestParam(value = "user") String data) {
JSONParser jp = new JSONParser(data);
System.out.println(jp);
LinkedHashMap<String, Object> userInfo;
try {
userInfo = jp.parseObject();
User user = userService.findUserByEmail(userInfo.get("email").toString());
System.out.println(user);
user.setAvatarExistance(true);
userService.updateUser(user);
// Employee employee = employeeService.findEmployeeByUser(user);
System.out.println(data);
new EmployeeManager(employeeService, userService).employeeProfileEdit(data);
if (file != null) {
System.out.println(file);
new AvatarManager(avatarService).saveAvatar(user, file);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// return "";
}
Post the file as request body (rather than as URL parameter and #RequestParam) to not excced the safe maximum URL length:
#RequestMapping(value = "/uploadFile", method = RequestMethod.POST)
#ResponseStatus(value = HttpStatus.OK)
public void uploadFile(ModelMap m, MultipartHttpServletRequest request) {
MultiValueMap<String, MultipartFile> multiFileMap = request.getMultiFileMap();
List<MultipartFile> files = multiFileMap.isEmpty() ? null : multiFileMap.values().iterator().next();
MultipartFile file = files != null && !files.isEmpty() ? files.get(0) : null;
// ...
}

Spring 4 , REST Service returns a 415 error from Tomcat

I am trying to test the POST method in a REST service with Spring 4. It works fine in my integration tests with MockMvcBuilders.standaloneSetup but I deployed it in a Tomcat 8.5.8 and I can no understand why it is not working. I receive this message:
HTTP Status 415 -
type Status report
message
description The server refused this request because the request entity
is in a format not supported by the requested resource for the
requested method.
________________
but the Tomcat Server receives this request (extracted from wireshark):
POST /app-1.0-SNAPSHOT/v1.0/concentrators/ HTTP/1.1
User-Agent: curl/7.35.0
Host: x.x.x.x:8080
Accept: */*
Content-Type: application/json
Content-Length: 528 {"street":"street","num":"num","code":"code","town":"town"
,"descriptionRoom":"descriptionRoom","btPwd":"btPwd"
,"gprsPwd":"gprsPwd","gprsLogin":"gprsLogin","gprsApn":"gprsApn"
,"gprsPin":"gprsPin","motherboardId":"motherboardId","logLevel":0
,"frameSendPeriod":0,"frameCapturePeriod":0,"mQTTServerPwd":"mQTTServerPwd"
,"mQTTServerUser":"mQTTServerUser","mQTTServerIp":"mQTTServerIp"
,"ftpServerPwd":"ftpServerPwd","ftpServerUser":"ftpServerUser"
, "ftpServerIp":"ftpServerIp","numSerie" :"numSerie","idConcentrator":-1,"infoCameras":[]}
It seems fine I don't know where is the mistake.
My REST service is:
#RequestMapping(value = "/", method = RequestMethod.POST, consumes = { "application/json" }, produces = { "application/json" })
public ResponseEntity<String> post(#RequestBody ConfigurationConcentrator configurationConcentrator) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
try {
configureConcentrator.create(configurationConcentrator);
} catch (IncorrectDBOperation | ErrorSendMessageException e) {
return new ResponseEntity<String>(e.getMessage(), headers, HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<String>(HttpStatus.CREATED);
}
Also, It checked the jackson dependencies (databind, core and annotations) and they are added in .war file.
This is my curl command:
curl -X POST -H "Content-Type: application/json" --data #addConcentrator2.json http://x.x.x.x:8080/app-1.0-SNAPSHOT/v1.0/concentrators/
It seems, It can not resolve correctly which interceptor needs, but I don't see the problem:
#RequestMapping(value = "/{id}", method = RequestMethod.GET, consumes = { "application/json" }, produces = { "application/json" })
public #ResponseBody ResponseEntity<ConfigurationConcentrator> get(#PathVariable("id") String id) {
....
}
#RequestMapping(value = "/", method = RequestMethod.POST, consumes = { "application/json" }, produces = { "application/json" })
public ResponseEntity<String> post(#RequestBody ConfigurationConcentrator configurationConcentrator) {
....
}
#RequestMapping(value = "/{id}", method = RequestMethod.PUT, consumes = { "application/json" }, produces = { "application/json" })
public ResponseEntity<String> put(#PathVariable("id") String id, #RequestBody ConfigurationConcentrator configurationConcentrator) {
....
}
#RequestMapping(value = "/{id}/cameras/{idcamera}", method = RequestMethod.PUT, consumes = { "application/json" }, produces = { "application/json" })
public ResponseEntity<String> putCameras(#PathVariable("id") String id, #PathVariable("idcamera") String idCamera,
....
}
#RequestMapping(value = "/{id}/cameras", method = RequestMethod.POST, consumes = { "application/json" }, produces = { "application/json" })
public ResponseEntity<String> postCameras(#PathVariable("id") String id, #RequestBody List<ConfigurationCamera> configurationCameras) {
....
}
#RequestMapping(value = "/{id}/initialconfiguration", method = RequestMethod.GET, consumes = { "application/json" }, produces = { "application/json" })
public ResponseEntity<StatusInitialConfiguration> getInitialConfiguration(#PathVariable("id") String numSerie) {
....
}
UPDATE1:
I updated the curl command with the Accept header.
curl -X POST -H "Content-Type: application/json" -H "Accept: application/json" --data #addConcentrator2.json http://x.x.x.x:8080/app-1.0-SNAPSHOT/v1.0/concentrators/
UPDATE2:
I think, It is detecting two interceptors:
06:36:41.011 [http-nio-8080-exec-8] DEBUG org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping - Mapping [/v1.0/concentrators/1/camera
s] to HandlerExecutionChain with handler [gasnatural.ConcentratorController#74e5ead6] and 2 interceptors
06:36:41.011 [http-nio-8080-exec-8] DEBUG org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver - Resolving exception from han
dler [gasnatural.ConcentratorController#74e5ead6]: org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/json' not supported
06:36:41.011 [http-nio-8080-exec-8] DEBUG org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver - Resolving exception from handler [gas
natural.ConcentratorController#74e5ead6]: org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/json' not supported
06:36:41.011 [http-nio-8080-exec-8] DEBUG org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver - Resolving exception from handler [gasnat
ural.ConcentratorController#74e5ead6]: org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/json' not supported
06:36:41.011 [http-nio-8080-exec-8] DEBUG org.springframework.web.servlet.DispatcherServlet - Null ModelAndView returned to DispatcherServlet with name 'dispatc
her': assuming HandlerAdapter completed request handling
06:36:41.011 [http-nio-8080-exec-8] DEBUG org.springframework.web.servlet.DispatcherServlet - Successfully completed request
UPDATE3:
Classes to map JSON:
Configuration concentrator
package gasnatural.models;
import java.util.ArrayList;
import java.util.List;
public class ConfigurationConcentrator {
public static class InfoCamera {
public Long idCamera;
public String numSerie;
}
private String street = null;
private String num = null;
private String code = null;
private String town = null;
private String descriptionRoom = null;
private String btPwd = null;
private String gprsPwd = null;
private String gprsLogin = null;
private String gprsApn = null;
private String gprsPin = null;
private String motherboardId = null;
private int logLevel = -1;
private int frameSendPeriod = -1;
private int frameCapturePeriod = -1;
private String mQTTServerPwd = null;
private String mQTTServerUser = null;
private String mQTTServerIp = null;
private String ftpServerPwd = null;
private String ftpServerUser = null;
private String ftpServerIp = null;
private String numSerie = null;
private Long idConcentrator;
private List<InfoCamera> infoCameras;
public ConfigurationConcentrator() {
}
public ConfigurationConcentrator(String street, String num, String town, String code, String descriptionRoom, String btPwd, String gprsPwd,
String gprsLogin, String gprsApn, String gprsPin, String motherboardId, int logLevel, int frameSendPeriod, int frameCapturePeriod,
String mQTTServerPwd, String mQTTServerUser, String mQTTServerIp, String ftpServerPwd, String ftpServerUser, String ftpServerIp, String numSerie) {
this(new Long(-1), street, num, town, code, descriptionRoom, btPwd, gprsPwd, gprsLogin, gprsApn, gprsPin, motherboardId, logLevel, frameSendPeriod,
frameCapturePeriod, mQTTServerPwd, mQTTServerUser, mQTTServerIp, ftpServerPwd, ftpServerUser, ftpServerIp, numSerie,
new ArrayList<InfoCamera>());
}
public ConfigurationConcentrator(Long idConcentrator, String street, String num, String town, String code, String descriptionRoom, String btPwd,
String gprsPwd, String gprsLogin, String gprsApn, String gprsPin, String motherboardId, int logLevel, int frameSendPeriod, int frameCapturePeriod,
String mQTTServerPwd, String mQTTServerUser, String mQTTServerIp, String ftpServerPwd, String ftpServerUser, String ftpServerIp, String numSerie,
List<InfoCamera> infoCameras) {
this.descriptionRoom = descriptionRoom;
this.btPwd = btPwd;
this.gprsPwd = gprsPwd;
this.gprsLogin = gprsLogin;
this.gprsApn = gprsApn;
this.gprsPin = gprsPin;
this.motherboardId = motherboardId;
this.logLevel = logLevel;
this.frameSendPeriod = frameSendPeriod;
this.frameCapturePeriod = frameCapturePeriod;
this.mQTTServerPwd = mQTTServerPwd;
this.mQTTServerUser = mQTTServerUser;
this.mQTTServerIp = mQTTServerIp;
this.ftpServerPwd = ftpServerPwd;
this.ftpServerUser = ftpServerUser;
this.ftpServerIp = ftpServerIp;
this.numSerie = numSerie;
this.street = street;
this.num = num;
this.code = code;
this.town = town;
this.descriptionRoom = descriptionRoom;
this.infoCameras = infoCameras;
this.idConcentrator = idConcentrator;
}
public void addIdCamera(InfoCamera idCamera) {
this.infoCameras.add(idCamera);
}
public String getStreet() {
return street;
}
public String getNum() {
return num;
}
public String getCode() {
return code;
}
public String getTown() {
return town;
}
public String getDescriptionRoom() {
return descriptionRoom;
}
public String getBtPwd() {
return btPwd;
}
public String getGprsPwd() {
return gprsPwd;
}
public String getGprsLogin() {
return gprsLogin;
}
public String getGprsApn() {
return gprsApn;
}
public String getGprsPin() {
return gprsPin;
}
public String getMotherboardId() {
return motherboardId;
}
public int getLogLevel() {
return logLevel;
}
public int getFrameSendPeriod() {
return frameSendPeriod;
}
public int getFrameCapturePeriod() {
return frameCapturePeriod;
}
public String getmQTTServerPwd() {
return mQTTServerPwd;
}
public String getmQTTServerUser() {
return mQTTServerUser;
}
public String getmQTTServerIp() {
return mQTTServerIp;
}
public String getFtpServerPwd() {
return ftpServerPwd;
}
public String getFtpServerUser() {
return ftpServerUser;
}
public String getFtpServerIp() {
return ftpServerIp;
}
public String getNumSerie() {
return numSerie;
}
public Long getIdConcentrator() {
return idConcentrator;
}
public List<InfoCamera> getInfoCameras() {
return infoCameras;
}
public void setStreet(String street) {
this.street = street;
}
public void setNum(String num) {
this.num = num;
}
public void setCode(String code) {
this.code = code;
}
public void setTown(String town) {
this.town = town;
}
public void setDescriptionRoom(String descriptionRoom) {
this.descriptionRoom = descriptionRoom;
}
public void setBtPwd(String btPwd) {
this.btPwd = btPwd;
}
public void setGprsPwd(String gprsPwd) {
this.gprsPwd = gprsPwd;
}
public void setGprsLogin(String gprsLogin) {
this.gprsLogin = gprsLogin;
}
public void setGprsApn(String gprsApn) {
this.gprsApn = gprsApn;
}
public void setGprsPin(String gprsPin) {
this.gprsPin = gprsPin;
}
public void setMotherboardId(String motherboardId) {
this.motherboardId = motherboardId;
}
public void setLogLevel(int logLevel) {
this.logLevel = logLevel;
}
public void setFrameSendPeriod(int frameSendPeriod) {
this.frameSendPeriod = frameSendPeriod;
}
public void setFrameCapturePeriod(int frameCapturePeriod) {
this.frameCapturePeriod = frameCapturePeriod;
}
public void setmQTTServerPwd(String mQTTServerPwd) {
this.mQTTServerPwd = mQTTServerPwd;
}
public void setmQTTServerUser(String mQTTServerUser) {
this.mQTTServerUser = mQTTServerUser;
}
public void setmQTTServerIp(String mQTTServerIp) {
this.mQTTServerIp = mQTTServerIp;
}
public void setFtpServerPwd(String ftpServerPwd) {
this.ftpServerPwd = ftpServerPwd;
}
public void setFtpServerUser(String ftpServerUser) {
this.ftpServerUser = ftpServerUser;
}
public void setFtpServerIp(String ftpServerIp) {
this.ftpServerIp = ftpServerIp;
}
public void setNumSerie(String numSerie) {
this.numSerie = numSerie;
}
public void setIdConcentrator(Long idConcentrator) {
this.idConcentrator = idConcentrator;
}
public void setInfoCameras(List<InfoCamera> infoCameras) {
this.infoCameras = infoCameras;
}
}
Configuration camera
package gasnatural.models;
public class ConfigurationCamera {
private String numSerie = null;
private String numCamera = null;
private String cups = null;
private String status = null;
public ConfigurationCamera() {
}
public ConfigurationCamera(String numSerie, String numCamera, String cups, String status) {
this.numSerie = numSerie;
this.numCamera = numCamera;
this.cups = cups;
this.status = status;
}
public String getStatus() {
return status;
}
public String getNumSerie() {
return numSerie;
}
public String getNumCamera() {
return numCamera;
}
public String getCups() {
return cups;
}
public void setNumSerie(String numSerie) {
this.numSerie = numSerie;
}
public void setNumCamera(String numCamera) {
this.numCamera = numCamera;
}
public void setCups(String cups) {
this.cups = cups;
}
public void setStatus(String status) {
this.status = status;
}
}
UPDATE4
I simplified the mapped object class , and I receive the same error.
public class DTOConfigurationConcentrator {
private String street;
private String num;
public DTOConfigurationConcentrator() {
super();
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public String getNum() {
return num;
}
public void setNum(String num) {
this.num = num;
}
}
It seems something related to the tool for the json serialization but I don't know exactly how I can check this.
I forgot to tag my configuration class with #EnableWebMvc...

Sprint Rest Content type 'application/json;charset=UTF-8' not supported

Calling a Controller from a Java service I have this issue
org.springframework.web.HttpMediaTypeNotSupportedException: Content
type 'application/json;charset=UTF-8' not supported
I do not understand what's wrong with my Java code
String url3 = "http://localhost:8889/galian/S/S/S/claimsWS/getContract1";
ContractDto contractDto = new ContractDto("Test", "20161111", "idTest");
RestTemplate restTemplate3 = null;
try {
restTemplate3 = getRestTemplate(new URI(url3));
}
catch (URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
HttpHeaders headers = new HttpHeaders();
//headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<ContractDto> requestEntity = new HttpEntity<ContractDto>(contractDto, headers);
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
Object responseEntity = restTemplate3.postForObject(url3, requestEntity, Object.class);
Map<String, Object> responseObject3 = restTemplate.postForObject(url3, contractDto, Map.class);
DTO
public class ContractDto implements Serializable {
private static final long serialVersionUID = -7597862463769066562L;
protected String contractId;
protected String claimDate;
protected String insuredObjectIdentifier;
public ContractDto() {
}
public ContractDto(String contractId, String claimDate, String insuredObjectIdentifier) {
this.contractId = contractId;
this.claimDate = claimDate;
this.insuredObjectIdentifier = insuredObjectIdentifier;
}
public String getContractId() {
return contractId;
}
public void setContractId(String contractId) {
this.contractId = contractId;
}
public String getClaimDate() {
return claimDate;
}
public void setClaimDate(String claimDate) {
this.claimDate = claimDate;
}
public String getInsuredObjectIdentifier() {
return insuredObjectIdentifier;
}
public void setInsuredObjectIdentifier(String insuredObjectIdentifier) {
this.insuredObjectIdentifier = insuredObjectIdentifier;
}
}
Controller
#Controller
#Lazy
#RequestMapping("/claimsWS")
#Transactional
public class ClaimsController {
...
#RequestMapping(value = "/getContract1", method = RequestMethod.POST)
public void getContract1(#RequestBody ClaimContractCriteriaDto contractCriteriaDto, HttpServletResponse response) throws IOException {
....
writeResult(response, contratBean);
}

Select JsonView in the Spring MVC Controller

I'm currently writing a REST api using Jackson (2.4.0-rc3) and spring mvc (4.0.3), and I'm trying to make it secure.
In this way, I try to use JsonView to select the parts of the objects that can be serialized.
I've found the solution (which is not for me) to annotate my Controller method with the view I want. But I'd like to select on the fly the view inside the controller.
Is it possible to extend the ResponseEntity class in order to specify which JsonView I want ?
A little piece of code :
Here is the account class
public class Account {
#JsonProperty(value = "account_id")
private Long accountId;
#JsonProperty(value = "mail_address")
private String mailAddress;
#JsonProperty(value = "password")
private String password;
#JsonProperty(value = "insert_event")
private Date insertEvent;
#JsonProperty(value = "update_event")
private Date updateEvent;
#JsonProperty(value = "delete_event")
private Date deleteEvent;
#JsonView(value = PublicView.class)
public Long getAccountId() {
return accountId;
}
#JsonView(value = PublicView.class)
public void setAccountId(Long accountId) {
this.accountId = accountId;
}
#JsonView(value = OwnerView.class)
public String getMailAddress() {
return mailAddress;
}
#JsonView(value = OwnerView.class)
public void setMailAddress(String mailAddress) {
this.mailAddress = mailAddress;
}
#JsonIgnore
public String getPassword() {
return password;
}
#JsonView(value = OwnerView.class)
public void setPassword(String password) {
this.password = password;
}
#JsonView(value = AdminView.class)
public Date getInsertEvent() {
return insertEvent;
}
#JsonView(value = AdminView.class)
public void setInsertEvent(Date insertEvent) {
this.insertEvent = insertEvent;
}
#JsonView(value = AdminView.class)
public Date getUpdateEvent() {
return updateEvent;
}
#JsonView(value = AdminView.class)
public void setUpdateEvent(Date updateEvent) {
this.updateEvent = updateEvent;
}
#JsonView(value = AdminView.class)
public Date getDeleteEvent() {
return deleteEvent;
}
#JsonView(value = OwnerView.class)
public void setDeleteEvent(Date deleteEvent) {
this.deleteEvent = deleteEvent;
}
#JsonProperty(value = "name")
public abstract String getName();
}
Here is the account controller
#RestController
#RequestMapping("/account")
public class AccountCtrlImpl implements AccountCtrl {
#Autowired
private AccountSrv accountSrv;
public AccountSrv getAccountSrv() {
return accountSrv;
}
public void setAccountSrv(AccountSrv accountSrv) {
this.accountSrv = accountSrv;
}
#Override
#RequestMapping(value = "/get_by_id/{accountId}", method = RequestMethod.GET, headers = "Accept=application/json")
public ResponseEntity<Account> getById(#PathVariable(value = "accountId") Long accountId) {
try {
return new ResponseEntity<Account>(this.getAccountSrv().getById(accountId), HttpStatus.OK);
} catch (ServiceException e) {
return new ResponseEntity<Account>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
#Override
#RequestMapping(value = "/get_by_mail_address/{mail_address}", method = RequestMethod.GET, headers = "Accept=application/json")
public ResponseEntity<Account> getByMailAddress(#PathVariable(value = "mail_address") String mailAddress) {
try {
return new ResponseEntity<Account>(this.getAccountSrv().getByMailAddress(mailAddress), HttpStatus.OK);
} catch (ServiceException e) {
return new ResponseEntity<Account>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
#Override
#RequestMapping(value = "/authenticate/{mail_address}/{password}", method = RequestMethod.GET, headers = "Accept=application/json")
public ResponseEntity<Account> authenticate(#PathVariable(value = "mail_address") String mailAddress, #PathVariable(value = "password") String password) {
return new ResponseEntity<Account>(HttpStatus.NOT_IMPLEMENTED);
}
}
I really like the solution presented here to dynamically select a json view inside your controller method.
Basically, you return a MappingJacksonValue which you construct with the value you want to return. After that you call setSerializationView(viewClass) with the proper view class. In my use case, I returned a different view depending on the current user, something like this:
#RequestMapping("/foos")
public MappingJacksonValue getFoo(#AuthenticationPrincipal UserDetails userDetails ) {
MappingJacksonValue value = new MappingJacksonValue( fooService.getAll() );
if( userDetails.isAdminUser() ) {
value.setSerializationView( Views.AdminView.class );
} else {
value.setSerializationView( Views.UserView.class );
}
return value;
}
BTW: If you are using Spring Boot, you can control if properties that have no view associated are serialized or not by setting this in your application.properties:
spring.jackson.mapper.default_view_inclusion=true
I've solved my problem extending ResponseEntity like this :
public class ResponseViewEntity<T> extends ResponseEntity<ContainerViewEntity<T>> {
private Class<? extends BaseView> view;
public ResponseViewEntity(HttpStatus statusCode) {
super(statusCode);
}
public ResponseViewEntity(T body, HttpStatus statusCode) {
super(new ContainerViewEntity<T>(body, BaseView.class), statusCode);
}
public ResponseViewEntity(T body, Class<? extends BaseView> view, HttpStatus statusCode) {
super(new ContainerViewEntity<T>(body, view), statusCode);
}
}
and ContainerViewEntity encapsulate the object and the selected view
public class ContainerViewEntity<T> {
private final T object;
private final Class<? extends BaseView> view;
public ContainerViewEntity(T object, Class<? extends BaseView> view) {
this.object = object;
this.view = view;
}
public T getObject() {
return object;
}
public Class<? extends BaseView> getView() {
return view;
}
public boolean hasView() {
return this.getView() != null;
}
}
After that, we have convert only the object with the good view.
public class JsonViewMessageConverter extends MappingJackson2HttpMessageConverter {
#Override
protected void writeInternal(Object object, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
if (object instanceof ContainerViewEntity && ((ContainerViewEntity) object).hasView()) {
writeView((ContainerViewEntity) object, outputMessage);
} else {
super.writeInternal(object, outputMessage);
}
}
protected void writeView(ContainerViewEntity view, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
JsonEncoding encoding = this.getJsonEncoding(outputMessage.getHeaders().getContentType());
ObjectWriter writer = this.getWriterForView(view.getView());
JsonGenerator jsonGenerator = writer.getFactory().createGenerator(outputMessage.getBody(), encoding);
try {
writer.writeValue(jsonGenerator, view.getObject());
} catch (IOException ex) {
throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getMessage(), ex);
}
}
private ObjectWriter getWriterForView(Class<?> view) {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, false);
return mapper.writer().withView(view);
}
}
And to finish, I enable the converter
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="wc.handler.view.JsonViewMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>
And that's it, I can select the View in the controller
#Override
#RequestMapping(value = "/get_by_id/{accountId}", method = RequestMethod.GET, headers = "Accept=application/json")
public ResponseViewEntity<Account> getById(#PathVariable(value = "accountId") Long accountId) throws ServiceException {
return new ResponseViewEntity<Account>(this.getAccountSrv().getById(accountId), PublicView.class, HttpStatus.OK);
}
FYI, Spring 4.1 already supported using #JsonView directly on #ResponseBody and ResponseEntity:
Jackson’s #JsonView is supported directly on #ResponseBody and ResponseEntity controller methods for serializing different amounts of detail for the same POJO (e.g. summary vs. detail page). This is also supported with View-based rendering by adding the serialization view type as a model attribute under a special key.
And in http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-jsonview you can find the much simpler solution:
#RestController
public class UserController {
#RequestMapping(value = "/user", method = RequestMethod.GET)
#JsonView(User.WithoutPasswordView.class)
public User getUser() {
return new User("eric", "7!jd#h23");
}
}
public class User {
public interface WithoutPasswordView {};
public interface WithPasswordView extends WithoutPasswordView {};
private String username;
private String password;
public User() {
}
public User(String username, String password) {
this.username = username;
this.password = password;
}
#JsonView(WithoutPasswordView.class)
public String getUsername() {
return this.username;
}
#JsonView(WithPasswordView.class)
public String getPassword() {
return this.password;
}
}
This works great :
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
public void getZone(#PathVariable long id, #RequestParam(name = "tree", required = false) boolean withChildren, HttpServletResponse response) throws IOException {
LOGGER.debug("Get a specific zone with id {}", id);
Zone zone = zoneService.findById(id);
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
if (withChildren) {
response.getWriter().append(mapper.writeValueAsString(zone));
} else {
response.getWriter().append(mapper.writerWithView(View.ZoneWithoutChildren.class).writeValueAsString(zone));
}
}

Categories