in my app I have controller:
package org.sample.web.config;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.sample.model.Contact;
import org.sample.model.Person;
import org.sample.model.PersonGender;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestMapping;
import ch.ralscha.extdirectspring.generator.IncludeValidation;
import ch.ralscha.extdirectspring.generator.ModelGenerator;
import ch.ralscha.extdirectspring.generator.OutputFormat;
#Controller
#RequestMapping
public class ModelController {
private final Logger logger = LoggerFactory.getLogger(getClass());
#InitBinder
public void initBinder(WebDataBinder binder) {
logger.error("aaaaaaaaaaaaaaa");
binder.registerCustomEditor(PersonGender.class, new EnumPropertyEditor(PersonGender.class));
}
#RequestMapping("/app/model/Person.js")
public void user(HttpServletRequest request, HttpServletResponse response) throws IOException {
ModelGenerator.writeModel(request, response, Person.class, OutputFormat.EXTJS4, IncludeValidation.ALL, true);
}
#RequestMapping("/app/model/Contact.js")
public void catalog(HttpServletRequest request, HttpServletResponse response) throws IOException {
ModelGenerator.writeModel(request, response, Contact.class, OutputFormat.EXTJS4, IncludeValidation.ALL, true);
}
}
problem is that method with annotation InitBinder is never calling so when I want to validate my enut it throws exception:
javax.validation.UnexpectedTypeException: HV000030: No validator could be found for type: org.sample.model.PersonGender.
at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorManager.verifyResolveWasUnique(ConstraintValidatorManager.java:218)
at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorManager.findMatchingValidatorClass(ConstraintValidatorManager.java:193)
at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorManager.getInitializedValidator(ConstraintValidatorManager.java:97)
at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateConstraints(ConstraintTree.java:125)
at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateConstraints(ConstraintTree.java:91)
at org.hibernate.validator.internal.metadata.core.MetaConstraint.validateConstraint(MetaConstraint.java:85)
at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraint(ValidatorImpl.java:478)
at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForDefaultGroup(ValidatorImpl.java:424)
at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForCurrentGroup(ValidatorImpl.java:388)
at org.hibernate.validator.internal.engine.ValidatorImpl.validateInContext(ValidatorImpl.java:340)
at org.hibernate.validator.internal.engine.ValidatorImpl.validate(ValidatorImpl.java:158)
at org.springframework.validation.beanvalidation.SpringValidatorAdapter.validate(SpringValidatorAdapter.java:102)
at org.springframework.validation.DataBinder.validate(DataBinder.java:772)
EDIT:
PersonGender:
package org.sample.model;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
public enum PersonGender implements Serializable {
MALE("M"), FEMALE("F"), UNKNOWN("0");
private static final long serialVersionUID = 1L;
private static Map<String, PersonGender> identifierMap = new HashMap<String, PersonGender>();
static {
for (PersonGender value : PersonGender.values()) {
identifierMap.put(value.getValue(), value);
}
}
private String value;
private PersonGender(String value) {
this.value = value;
}
public static PersonGender fromValue(String value) {
PersonGender result = identifierMap.get(value);
if (result == null) {
throw new IllegalArgumentException("No PersonGender for value: " + value);
}
return result;
}
public String getValue() {
return value;
}
public String getName() {
return name();
}
}
EXCEPTIon occurs when submiting form:
#Service
public class SimpleService {
...
#ExtDirectMethod(value = ExtDirectMethodType.FORM_POST, group = "person")
public ExtDirectFormPostResult validatePersonForm(#Valid Person p, BindingResult result) {
if (!result.hasErrors()) {
// another validations
}
return new ExtDirectFormPostResult(result);
}
...
}
Related
I'm trying to build an API with Spring Boot, but I keep getting an error when dealing with #OneToMany entities. The Bean seem to not be able to get an entity I'm referencing by ID through the JSON from the database and constructing it to insert into the other entity. Sounds complicated, so here's the code for everything and the error. I googled and googled and couldn't find a fitting answer to my specific situation.
Entity Turma:
package com.residencia.academia.entity;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
#Entity
#Table(name = "turma")
public class Turma {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id_turma")
private Integer idTurma;
#Column(name = "horario")
private Date horarioTurma;
#Column(name = "duracao")
private Integer duracaoTurma;
#Column(name = "data_inicio")
private Date dataInicioTurma;
#Column(name = "data_fim")
private Date dataFimTurma;
#ManyToOne
#JoinColumn(name = "id_instrutor", referencedColumnName = "id_instrutor")
private Instrutor instrutor;
public Integer getIdTurma() {
return idTurma;
}
public void setIdTurma(Integer idTurma) {
this.idTurma = idTurma;
}
public Date getHorarioTurma() {
return horarioTurma;
}
public void setHorarioTurma(Date horarioTurma) {
this.horarioTurma = horarioTurma;
}
public Integer getDuracaoTurma() {
return duracaoTurma;
}
public void setDuracaoTurma(Integer duracaoTurma) {
this.duracaoTurma = duracaoTurma;
}
public Date getDataInicioTurma() {
return dataInicioTurma;
}
public void setDataInicioTurma(Date dataInicioTurma) {
this.dataInicioTurma = dataInicioTurma;
}
public Date getDataFimTurma() {
return dataFimTurma;
}
public void setDataFimTurma(Date dataFimTurma) {
this.dataFimTurma = dataFimTurma;
}
public Instrutor getInstrutor() {
return instrutor;
}
public void setInstrutor(Instrutor instrutor) {
this.instrutor = instrutor;
}
}
Turma's Controller:
package com.residencia.academia.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.residencia.academia.entity.Turma;
import com.residencia.academia.service.TurmaService;
#RestController
#RequestMapping("/turma")
public class TurmaController {
#Autowired
private TurmaService turmaService;
#GetMapping
public ResponseEntity<List<Turma>> findAll() {
return ResponseEntity.ok().body(turmaService.findAllTurma());
}
#GetMapping("/{id}")
public ResponseEntity<Turma> findById(#PathVariable Integer id) {
return ResponseEntity.ok().body(turmaService.findByIdTurma(id));
}
#PostMapping
public Turma save(#RequestBody Turma turma) {
return turmaService.saveTurma(turma);
}
#PutMapping
public Turma update(#RequestBody Turma turma) {
return turmaService.updateTurma(turma);
}
#DeleteMapping("/{id}")
public void delete(#PathVariable Integer id) {
turmaService.deleteTurma(id);
}
}
Turma's Service:
package com.residencia.academia.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.residencia.academia.entity.Turma;
import com.residencia.academia.repository.TurmaRepository;
#Service
public class TurmaService {
#Autowired
private TurmaRepository turmaRepository;
public List<Turma> findAllTurma() {
return turmaRepository.findAll();
}
public Turma findByIdTurma(Integer id) {
return turmaRepository.findById(id).get();
}
public Turma saveTurma(Turma turma) {
return turmaRepository.save(turma);
}
public Turma updateTurma(Turma turma) {
return turmaRepository.save(turma);
}
public void deleteTurma(Integer id) {
turmaRepository.deleteById(id);
}
public void deleteTurma(Turma turma) {
turmaRepository.delete(turma);
}
}
Turma's Repository:
package com.residencia.academia.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.residencia.academia.entity.Turma;
public interface TurmaRepository extends JpaRepository<Turma, Integer> {
}
Entity Instrutor:
package com.residencia.academia.entity;
import java.util.Date;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
#Entity
#Table(name = "instrutor")
public class Instrutor {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id_instrutor")
private Integer idInstrutor;
#Column(name = "rg")
private Integer rgInstrutor;
#Column(name = "nome")
private String nomeInstrutor;
#Column(name = "nascimento")
private Date dataNascimentoInstrutor;
#Column(name = "titulacao")
private Integer titulacaoInstrutor;
#OneToMany(mappedBy = "instrutor")
private List<Turma> turmaList;
public Integer getIdInstrutor() {
return idInstrutor;
}
public void setIdInstrutor(Integer idInstrutor) {
this.idInstrutor = idInstrutor;
}
public Integer getRgInstrutor() {
return rgInstrutor;
}
public void setRgInstrutor(Integer rgInstrutor) {
this.rgInstrutor = rgInstrutor;
}
public String getNomeInstrutor() {
return nomeInstrutor;
}
public void setNomeInstrutor(String nomeInstrutor) {
this.nomeInstrutor = nomeInstrutor;
}
public Date getDataNascimentoInstrutor() {
return dataNascimentoInstrutor;
}
public void setDataNascimentoInstrutor(Date dataNascimentoInstrutor) {
this.dataNascimentoInstrutor = dataNascimentoInstrutor;
}
public Integer getTitulacaoInstrutor() {
return titulacaoInstrutor;
}
public void setTitulacaoInstrutor(Integer titulacaoInstrutor) {
this.titulacaoInstrutor = titulacaoInstrutor;
}
public List<Turma> getTurmaList() {
return turmaList;
}
public void setTurmaList(List<Turma> turmaList) {
this.turmaList = turmaList;
}
}
Instrutor's Controller:
package com.residencia.academia.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.residencia.academia.entity.Instrutor;
import com.residencia.academia.service.InstrutorService;
#RestController
#RequestMapping("/instrutor")
public class InstrutorController {
#Autowired
private InstrutorService instrutorService;
#GetMapping
public ResponseEntity<List<Instrutor>> findAll() {
return ResponseEntity.ok().body(instrutorService.findAllInstrutor());
}
#GetMapping("/{id}")
public ResponseEntity<Instrutor> findById(#PathVariable Integer id) {
return ResponseEntity.ok().body(instrutorService.findByIdInstrutor(id));
}
#PostMapping
public Instrutor save(#RequestBody Instrutor instrutor) {
return instrutorService.saveInstrutor(instrutor);
}
#PutMapping
public Instrutor update(#RequestBody Instrutor instrutor) {
return instrutorService.updateInstrutor(instrutor);
}
#DeleteMapping("/{id}")
public void delete(#PathVariable Integer id) {
instrutorService.deleteInstrutor(id);
}
}
Instrutor's Service:
package com.residencia.academia.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.residencia.academia.entity.Instrutor;
import com.residencia.academia.repository.InstrutorRepository;
#Service
public class InstrutorService {
#Autowired
private InstrutorRepository instrutorRepository;
public List<Instrutor> findAllInstrutor() {
return instrutorRepository.findAll();
}
public Instrutor findByIdInstrutor(Integer id) {
return instrutorRepository.findById(id).get();
}
public Instrutor saveInstrutor(Instrutor instrutor) {
return instrutorRepository.save(instrutor);
}
public Instrutor updateInstrutor(Instrutor instrutor) {
return instrutorRepository.save(instrutor);
}
public void deleteInstrutor(Integer id) {
instrutorRepository.deleteById(id);
}
public void deleteInstrutor(Instrutor instrutor) {
instrutorRepository.delete(instrutor);
}
}
Instrutor's Repository:
package com.residencia.academia.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.residencia.academia.entity.Instrutor;
public interface InstrutorRepository extends JpaRepository<Instrutor, Integer> {
}
JSON Structure:
{
"horarioTurma": "2022-06-29T18:00:00",
"duracaoTurma": 60,
"dataInicioTurma": "2022-06-29",
"dataFimTurma": "2022-07-29",
"instrutor": 1
}
HTTP Response:
400 Bad Request
org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of `com.residencia.academia.entity.Instrutor` (although at least one Creator exists): no int/Int-argument constructor/factory method to deserialize from Number value (1)
Any help is appreciated!
How to retrieve data from ligneCommandeDto and pass it to lignebpdto to generate dynamically a lignebpService from ligneCommandeService if affercter() is true.
the affercter() method for checking if the isAffected attribute is true, if that I call the genererbp() methode , this methode create a ligneBp so I need to fill il with data from ligneCommandeDTO.
package org.backend.gcmd.service;
import org.backend.gcmd.dto.LigneBpDTO;
import org.backend.gcmd.dto.LigneCommandeDTO;
import org.backend.gcmd.entity.LigneCommandeEntity;
import org.backend.gcmd.exceptions.technical.ObjectNotFoundException;
import org.backend.gcmd.mapper.LigneCommandeMapper;
import org.backend.gcmd.repository.LigneCommandeRepository;
import org.backend.gcmd.validator.Validate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Optional;
import static java.util.stream.Collectors.toList;
#Service
#Transactional
public class LigneCommandeService {
#Autowired
private LigneCommandeRepository ligneCommandeRepository;
#Autowired
private LigneCommandeMapper ligneCommandeMapper;
#Autowired
private LigneBpService ligneBpService;
private LigneBpDTO ligneBpDTO;
#Autowired
private LigneBpMapper ligneBpMapper;
public LigneCommandeDTO findById(Long id) {
Validate.notNull(id, "id mus be not null");
Optional<LigneCommandeEntity> entity = ligneCommandeRepository.findById(id);
if (entity.isPresent()) {
return ligneCommandeMapper.convertToDto(entity.get());
} else {
throw new ObjectNotFoundException("LigneCommandeDTO not found");
}
}
public LigneCommandeDTO save(LigneCommandeDTO dto) {
Validate.notNull(dto, "LigneCommandeDTO must be not null");
LigneCommandeEntity entity = ligneCommandeMapper.convertToEntity(dto);
LigneCommandeEntity saved = ligneCommandeRepository.save(entity);
return ligneCommandeMapper.convertToDto(saved);
}
public LigneCommandeDTO update(LigneCommandeDTO dto) {
Validate.notNull(dto, "LigneCommandeDTO must be not null");
Validate.notNull(dto.getId(), "LigneCommandeDTO id must be not null");
findById(dto.getId());
LigneCommandeEntity entity = ligneCommandeMapper.convertToEntity(dto);
LigneCommandeEntity saved = ligneCommandeRepository.save(entity);
return ligneCommandeMapper.convertToDto(saved);
}
public Page<LigneCommandeDTO> findAllByDeletedFalse(Pageable pageable) {
Page<LigneCommandeEntity> page = ligneCommandeRepository.findAllByDeletedFalse(pageable);
return ligneCommandeMapper.convertToPageDto(page);
}
public LigneCommandeDTO affecter(Long id, Boolean isAffected) {
Validate.notNull(id, "LigneCommandeDTO must be not null");
Validate.notNull(isAffected, "LigneCommandeDTO id must be not null");
LigneCommandeDTO lcdto = findById(id);
lcdto.setIsAffected(isAffected);
update(lcdto);
genererbp();
return null;
}
public LigneBpDTO genererbp(LigneCommandeDTO ligneCommandeDTO) {
if (ligneCommandeDTO.getIsAffected()) {
return ligneBpService.findAllByDeletedFalse((Pageable) ligneBpDTO)
.stream()
.map(ligneBpMapper::convertToDto)
.collect(toList());
}
return null;
}
}
the mapper class
package org.backend.gcmd.mapper;
import org.springframework.data.domain.Page;
import java.util.List;
public interface Mapper<D, E> {
Page<D> convertToPageDto(Page<E> page);
D convertToDto(E entity);
E convertToEntity(D dto);
List<D> convertToDtoList(List<E> entities);
List<E> convertToEntitiesList(List<D> entities);
}
package org.backend.gcmd.mapper;
import org.backend.gcmd.dto.LigneBpDTO;
import org.backend.gcmd.entity.LigneBpEntity;
import org.backend.gcmd.repository.BulltinPrestationRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
#Component
public class LigneBpMapper implements Mapper<LigneBpDTO, LigneBpEntity> {
#Autowired
BulltinPrestationRepository bulltinprestationRepository;
#Override
public Page<LigneBpDTO> convertToPageDto(Page<LigneBpEntity> page) {
return page.map(this::convertToDto);
}
#Override
public LigneBpDTO convertToDto(LigneBpEntity entity) {
LigneBpDTO dto = new LigneBpDTO();
dto.setId(entity.getId());
dto.setDate(entity.getDate());
dto.setHeure(entity.getHeure());
dto.setNombre(entity.getNombre());
dto.setPrestation(entity.getPrestation());
dto.setProduit(entity.getProduit());
dto.setSensTrafic(entity.getSensTrafic());
dto.setTarifUnifie(entity.getTarifUnifie());
dto.setTcConv(entity.getTcConv());
dto.setTcSuppl(entity.getTcSuppl());
dto.setTonnageMinimum(entity.getTonnageMinimum());
dto.setTonnageReel(entity.getTonnageReel());
return dto;
}
#Override
public LigneBpEntity convertToEntity(LigneBpDTO dto) {
LigneBpEntity entity = new LigneBpEntity();
entity.setId(dto.getId());
entity.setDate(dto.getDate());
entity.setHeure(dto.getHeure());
entity.setNombre(dto.getNombre());
entity.setPrestation(dto.getPrestation());
entity.setProduit(dto.getProduit());
entity.setSensTrafic(dto.getSensTrafic());
entity.setTarifUnifie(dto.getTarifUnifie());
entity.setTcConv(dto.getTcConv());
entity.setTcSuppl(dto.getTcSuppl());
entity.setTonnageMinimum(dto.getTonnageMinimum());
entity.setTonnageReel(dto.getTonnageReel());
return entity;
}
#Override
public List<LigneBpDTO> convertToDtoList(List<LigneBpEntity> entities) {
return entities.stream().map(this::convertToDto).collect(Collectors.toCollection(ArrayList::new));
}
#Override
public List<LigneBpEntity> convertToEntitiesList(List<LigneBpDTO> dtos) {
return dtos.stream().map(this::convertToEntity).collect(Collectors.toCollection(ArrayList::new));
}
}
controller
package org.backend.gcmd.controller;
import org.backend.gcmd.dto.LigneBpDTO;
import org.backend.gcmd.dto.LigneCommandeDTO;
import org.backend.gcmd.service.LigneBpService;
import org.backend.gcmd.service.LigneCommandeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
#RestController
#RequestMapping("/api/gcmd/v1/ligneCommandes")
public class LigneCommandeController {
#Autowired
private LigneCommandeService ligneCommandeService;
#GetMapping("{id}")
public ResponseEntity<LigneCommandeDTO> findById(#PathVariable Long id) {
LigneCommandeDTO ligneCommandeDTO = ligneCommandeService.findById(id);
return ResponseEntity.status(HttpStatus.OK).body(ligneCommandeDTO);
}
#PostMapping
public ResponseEntity<LigneCommandeDTO> save(#RequestBody LigneCommandeDTO ligneCommandeDTO) {
return ResponseEntity.status(HttpStatus.CREATED).body(ligneCommandeService.save(ligneCommandeDTO));
}
#PutMapping("{id}")
public ResponseEntity<LigneCommandeDTO> update(#PathVariable Long id,
#RequestBody LigneCommandeDTO ligneCommandeDTO) {
ligneCommandeDTO.setId(id);
return ResponseEntity.status(HttpStatus.ACCEPTED).body(ligneCommandeService.update(ligneCommandeDTO));
}
#GetMapping
public ResponseEntity<Page<LigneCommandeDTO>> findAllByDeletedFalse(Pageable pageable) {
return ResponseEntity.status(HttpStatus.OK).body(ligneCommandeService.findAllByDeletedFalse(pageable));
}
}
I'm trying to create custom jackson annotation that would affect serialization value.
Meaning:
class X {
#Unit("mm") int lenght;
...
}
Now serializaling object X(10) would result in:
{
"lenght" : "10 mm"
}
How can I achieve that?
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.IOException;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
// Create own annotation storing your unit value
#Target({ ElementType.FIELD })
#Retention(RetentionPolicy.RUNTIME)
#interface Unit {
String value();
}
// Create custom serializer checking #Unit annotation
class UnitSerializer extends StdSerializer<Integer> implements ContextualSerializer {
private String unit;
public UnitSerializer() {
super(Integer.class);
}
public UnitSerializer(String unit) {
super(Integer.class);
this.unit = unit;
}
#Override
public void serialize(Integer value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
jgen.writeString(String.format("%d %s", value, unit));
}
#Override
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
String unit = null;
Unit ann = null;
if (property != null) {
ann = property.getAnnotation(Unit.class);
}
if (ann != null) {
unit = ann.value();
}
return new UnitSerializer(unit);
}
}
#NoArgsConstructor
#AllArgsConstructor
#Data
class X {
#JsonSerialize(using = UnitSerializer.class)
#Unit("mm")
private int length;
}
public class Runner {
public static void main(String[] args) throws JsonProcessingException {
X x = new X(10);
ObjectMapper objectMapper = new ObjectMapper();
System.out.println(objectMapper.writeValueAsString(x));
}
}
Result:
{"length":"10 mm"}
Is there any possibility to validate StandardMultipartHttpServletRequest using standard #Valid annotation and custom Validator?
I've implemented such validator, annotated method param in controller the validator is not invoked.
I've figured it out myself. To make it work you need a DTO:
import lombok.Getter;
import lombok.Setter;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
#Getter
#Setter
public class NewOrderFilesDTO {
List<MultipartFile> files;
}
Then, a validator:
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
import static org.springframework.util.CollectionUtils.isEmpty;
#Component
public class NewOrderFilesValidator implements Validator {
private static final String MIME_TYPE_PDF = "application/pdf";
private static final long ALLOWED_SIZE = 3 * 1024 * 1024;
#Override
public void validate(Object target, Errors errors) {
if (target == null) {
return;
}
NewOrderFilesDTO newOrderFilesDTO = (NewOrderFilesDTO) target;
List<MultipartFile> newOrderFiles = newOrderFilesDTO.getFiles();
if (isEmpty(newOrderFiles)) {
return;
}
for (MultipartFile file : newOrderFiles) {
if (!MIME_TYPE_PDF.equals(file.getContentType())) {
errors.rejectValue(file.getName(), file.getName(), "'application/pdf' files allowed only!");
}
if (file.getSize() > ALLOWED_SIZE) {
errors.rejectValue(file.getName(), file.getName(), "File size allowed up to 3MB!");
}
}
}
#Override
public boolean supports(Class<?> cls) {
return NewOrderFilesDTO.class.equals(cls);
}
}
And finally a controller:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import javax.validation.Valid;
import static org.springframework.http.HttpStatus.NO_CONTENT;
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;
import static org.springframework.web.bind.annotation.RequestMethod.POST;
#Controller
class OrderController {
private final NewOrderFilesValidator newOrderFilesValidator;
#Autowired
OrderController(NewOrderFilesValidator newOrderFilesValidator) {
this.newOrderFilesValidator = newOrderFilesValidator;
}
#InitBinder("newOrderFiles")
void initOrderFilesBinder(WebDataBinder binder) {
binder.addValidators(newOrderFilesValidator);
}
#ResponseStatus(NO_CONTENT)
#RequestMapping(value = ORDERS_PATH, method = POST, consumes = MULTIPART_FORM_DATA_VALUE)
void createOrder(
#Valid #ModelAttribute NewOrderFilesDTO newOrderFiles
) {
}
}
With the configuration above the DTO will be validated automatically by spring.
Same #JsonIgnore applied to both String and List. It is working on String but not List.
Jackson version 2.3.0. Below is the sample program to print out the output for setter properties. Setter properties still shown for testList property.
The workaround might be mapper.disable(MapperFeature.USE_GETTERS_AS_SETTERS); but it is not my desired behaviour. I want to control on the object itself.
package my.com.myriadeas.ilmu.bootstrap;
import java.util.Iterator;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.BeanDeserializerBuilder;
import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
import com.fasterxml.jackson.databind.deser.SettableBeanProperty;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.type.TypeFactory;
public class JsonFactoryTest {
/**
* #param args
* #throws JsonMappingException
*/
public static void main(String[] args) throws JsonMappingException {
ObjectMapper mapper = new ObjectMapper();
//mapper.disable(MapperFeature.USE_GETTERS_AS_SETTERS);
mapper.registerModule(new TestJacksonModule());
JavaType javaType = TypeFactory.defaultInstance().uncheckedSimpleType(
TestJsonProperty.class);
System.out.println(mapper.canDeserialize(javaType));
}
public static class TestJsonProperty {
#JsonIgnore
private String testString;
#JsonProperty
public String getTestString() {
return testString;
}
#JsonIgnore
public void setTestString(String testString) {
this.testString = testString;
}
#JsonIgnore
private List<String> testList;
#JsonProperty
public List<String> getTestList() {
return testList;
}
#JsonIgnore
public void setTestList(List<String> testList) {
this.testList = testList;
}
}
public static class TestJacksonModule extends SimpleModule {
/**
*
*/
private static final long serialVersionUID = -8628204972239032380L;
public TestJacksonModule() {
setDeserializerModifier(new AssociationUriResolvingDeserializerModifier());
}
}
private static class AssociationUriResolvingDeserializerModifier extends
BeanDeserializerModifier {
public AssociationUriResolvingDeserializerModifier() {
}
#Override
public BeanDeserializerBuilder updateBuilder(
DeserializationConfig config, BeanDescription beanDesc,
BeanDeserializerBuilder builder) {
Iterator<SettableBeanProperty> properties = builder.getProperties();
while (properties.hasNext()) {
System.out.println("deserialize property= " + properties.next());
}
return builder;
}
}
}