Current group in class level bean validation - java

I have some group validations in a bean:
#FichaValida(groups={Ficha.DatosGenerales.class, Ficha.Economia.class})
public class Ficha {
public interface DatosGenerales{}
public interface Documentos{}
public interface Ubigeo{}
public interface Economia{}
#NotEmpty(groups = {DatosGenerales.class})
String apPrimer;
#NotEmpty(groups = {DatosGenerales.class})
String apSegundo;
#NotEmpty(groups = {DatosGenerales.class})
String preNombres;
#NotEmpty(groups = {Documentos.class})
String tiDocumento;
#NotEmpty(groups = {Documentos.class})
String nuDocumento;
#NotEmpty(groups = {Ubigeo.class})
String deDepartamento;
#NotEmpty(groups = {Ubigeo.class})
String deProvincia;
#NotEmpty(groups = {Ubigeo.class})
String deDistrito;
#NotEmpty(groups = {Economia.class})
String nuIngreso;
#NotEmpty(groups = {Economia.class})
String nuGasto;
//members, setters and getters
}
And these methods:
#RequestMapping(value = "datos-generales.do", method = RequestMethod.POST)
public String datosGenerales(
#Validated({Ficha.DatosGenerales.class}) Ficha ficha,
BindingResult bindingResult){
}
#RequestMapping(value = "documentos.do", method = RequestMethod.POST)
public String documentos(
#Validated({Ficha.Documentos.class}) Ficha ficha,
BindingResult bindingResult){
}
#RequestMapping(value = "economia.do", method = RequestMethod.POST)
public String economia(
#Validated({Ficha.Economia.class}) Ficha ficha,
BindingResult bindingResult){
}
How I can know in the validator class which group is currently validating?
public class FichaValidator implements ConstraintValidator<FichaValida, Ficha> {
private FichaValida fichaValida;
public void initialize(FichaValida fichaValida) {
this.fichaValida = fichaValida;
}
public boolean isValid(Ficha ficha, ConstraintValidatorContext constraintValidatorContext) {
/*
if(Ficha.DatosGenerales.class==...){
//some validations
}else if(Ficha.Economia.class==...){
//some validations
}
*/
return true;
}
}
I need to do validations with the members according the current group validation, by example if DatosGenerales group is validating, only use members related to it.

public boolean isValid(Ficha ficha, ConstraintValidatorContext constraintValidatorContext) {
if(Ficha.DatosGenerales.class==this.fichaValida.value()){
//some validations
}else if(Ficha.Economia.class==this.fichaValida.value()){
//some validations
}
return true;
}

Related

Why is Mongodb #Indexed(unique=true) not working?

My controller:
#PostMapping
public ResponseEntity<UserCreateResponse> createUser(#RequestBody #Valid UserCreateRequest userDto,
BindingResult result)
throws InvalidRequestException {
if (result.hasErrors()) {
throw new InvalidRequestException("Request parameter validation failed");
} else {
return ResponseEntity.ok(userService.createUser(userDto));
}
}
Service:
public UserCreateResponse createUser(UserCreateRequest userDto) {
return convertEntityToDto(userRepository.insert(convertDtoToEntity(userDto)));
}
private User convertDtoToEntity(UserCreateRequest userDto) {
return modelMapper.map(userDto, User.class);
}
private UserCreateResponse convertEntityToDto(User user) {
return modelMapper.map(user, UserCreateResponse.class);
}
And the model is :
#Getter
#Setter
#Document("User")
public class User {
#Id
private String id;
#Indexed(unique = true)
private String userName;
private String name;
private String surname;
private String job;
}
Repository is just a class extending MongoRepository.
When I try to insert 2 User with same userName via postman post request, it is adding 2 exactly same item to db even if I specified #Indexed(unique = true) to userName field. Why does this happen and how can I fix it on Java side without breaking indexing function on the field(I want to index userName field to find faster)

Spring Boot: Controller doesn't take in account Validator

I'm trying to accomplish the use of a validator into the controller. The two fields origin and destination should be of three capital letters as IATA Code. But it acts without filter, and any request is accepted.
Set of validator interface:
#Documented
#Constraint(validatedBy = IATACodeValidator.class)
#Target({ElementType.METHOD, ElementType.FIELD})
#Retention(RetentionPolicy.RUNTIME)
public #interface IATACodeConstraint {
String message() default "Invalid IATA code";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
Class of Validator:
public class IATACodeValidator implements ConstraintValidator<IATACodeConstraint, String> {
#Override
public void initialize(IATACodeConstraint iataCode) {
}
#Override
public boolean isValid(String codeField, ConstraintValidatorContext context) {
return codeField != null && codeField.matches("^[A-Z]{3}+$")
&& (codeField.length() == 3);
}
Basic class:
public class CrazyAirRequest {
#IATACodeConstraint
private String origin;
#IATACodeConstraint
private String destination;
private String departureDate;
private String returnDate;
private int passengerCount;
// getters & setters
Controller:
#RestController
#RequestMapping("flights")
#Validated
public class BusyFlightsController {
CrazyAirDatabase crazyAirService;
ToughJetDatabase toughJetService;
#Autowired
public BusyFlightsController(CrazyAirDatabase crazyAirService, ToughJetDatabase toughJetService) {
this.crazyAirService = new CrazyAirDatabase();
this.toughJetService = new ToughJetDatabase();
}
#RequestMapping(value = "/crazy-air-response", method = RequestMethod.GET)
public List<CrazyAirResponse> getCrazyAirResponse(
#RequestParam("origin") String origin,
#RequestParam("destination") String destination,
#RequestParam("departureDate") String departureDate,
#RequestParam("returnDate") String returnDate,
#RequestParam("passengerCount") int passengerCount
) {
CrazyAirRequest crazyAirRequest = new CrazyAirRequest(origin, destination, departureDate, returnDate,
passengerCount);
return crazyAirService.getCrazyAirResponse(crazyAirRequest);
}
You can directly use #Pattern annotation without creating a custom validator for two fields as shown below :
#Pattern(regexp ="^[A-Z]{3}" message ="Invalid IATA code")
private String origin;
#Pattern(regexp ="^[A-Z]{3}" message ="Invalid IATA code")
private String destination;
#virendra chauhan: thank you for your inspiration.
I solved so:
#RequestMapping(value = "/crazy-air-response", method = RequestMethod.GET)
public List<CrazyAirResponse> getCrazyAirResponse(
#RequestParam("origin") #Pattern(regexp = "^[A-Z]{3}", message = "Invalid IATA code")
String origin,
#RequestParam("destination") #Pattern(regexp = "^[A-Z]{3}", message = "Invalid IATA code")
String destination,
#RequestParam("departureDate") String departureDate,
#RequestParam("returnDate") String returnDate,
#RequestParam("passengerCount") int passengerCount
) {
CrazyAirRequest crazyAirRequest = new CrazyAirRequest(origin, destination, departureDate, returnDate,
passengerCount);
return crazyAirService.getCrazyAirResponse(crazyAirRequest);
}

pass abstract parameter to requestMapping function with spring boot

I have an abstract class "Agent"
and 3 other subclasses "Developer", "Support" and "Admin"
Here is the code source of "Agent" :
#Entity
#Table(name = "agents")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "role", discriminatorType =
DiscriminatorType.STRING, length = 3)
public abstract class Agent implements Serializable {
#Id
#GeneratedValue
private int id;
private String name;
private String lastName;
.........}
The code source of "Developer" classe
#Entity
#DiscriminatorValue("dev")
public class Developer extends Agent {
/*------------------- constructors -------------------*/
public Developer() {
super();
}
public Developer(String name, String lastName, ....) {
super(name, lastName, ...);
}
}
The rest of the classes "Admin", "Supprort" has the same form.
Here is my controller code Admin controller :
#Controller
public class AdminController {
/*------- attributs -------*/
#Autowired
#Resource(name = "admin")
private IAdmin iAdmin;
#Autowired
private AgentValidator agentValidator;
........
#RequestMapping(value = "/admin/save/developer", method = RequestMethod.POST)
public String createAgentAccount(Model model, String admin_id, String confirmPassword, String action, #ModelAttribute("agent") Developer developer, BindingResult result) {
Agent admin = iAdmin.profile(Integer.parseInt(admin_id));
developer.setConfirmPassword(confirmPassword);
agentValidator.validate(developer, result);
if (result.hasErrors()) {
model.addAttribute("action", action);
return "formAgents";
}
if (action.equals("create")) {
iAdmin.createAgent(admin, developer);
} else {
iAdmin.updateAgent(admin, developer);
}
return "redirect:/admin/show/agents";
}
.......
As you see this function create and update the developer account, But i need to save all agents types [admin, developer, support], I try this :
public String createAgentAccount(Model model, ... , #ModelAttribute("agent") Agent developer, BindingResult result) {.....}
But i get this error :
Tue Aug 22 19:54:03 WEST 2017
There was an unexpected error (type=Internal Server Error, status=500).
Failed to instantiate [com.GemCrmTickets.entities.Agent]: Is it an abstract class?; nested exception is java.lang.InstantiationException
I know that is impossible to instanciate an abstract Class. I don't want to do a function for each type of agent, One for all will be the best solution. So i need your help please. And thank you.
Your answer is one word. Use Ad hoc polymorphism, which means you can have multiple methods of createAgentAccount, then in each of them call an other method to handle the details.
UPDATE
This is what I think you want
#RequestMapping(value = "/admin/save/developer", method = RequestMethod.POST)
public String createAgentAccount(Model model, String admin_id, String confirmPassword, String action, #ModelAttribute("agent") Developer developer, BindingResult result) {
return createAgentAccount(model, admin_id, confirmPassword, action, developer, result);
}
#RequestMapping(value = "/admin/save/support", method = RequestMethod.POST)
public String createAgentAccount(Model model, String admin_id, String confirmPassword, String action, #ModelAttribute("agent") Support support, BindingResult result) {
return createAgentAccount(model, admin_id, confirmPassword, action, support, result);
}
private String createAccount(Model model, String admin_id, String confirmPassword, String action, Agent agent, BindingResult result) {
Agent admin = iAdmin.profile(Integer.parseInt(admin_id));
agent.setConfirmPassword(confirmPassword);
agentValidator.validate(agent, result);
if (result.hasErrors()) {
model.addAttribute("action", action);
return "formAgents";
}
if (action.equals("create")) {
iAdmin.createAgent(admin, agent);
} else {
iAdmin.updateAgent(admin, agent);
}
return "redirect:/admin/show/agents";
}

Get data from a repository using Spring

Ok so I am new to spring and don't really know how this works. I have been trying a few things and think its close to doing it but not getting any data from the server and giving me this error
Unsatisfied dependency expressed through constructor argument with index 4 of type [jp.co.fusionsystems.dimare.crm.service.impl.MyDataDefaultService]: : Error creating bean with name 'MyDataDefaultService' defined in file
My end point
//mobile data endpoint
#RequestMapping(
value = API_PREFIX + ENDPOINT_MyData + "/getMyData",
method = RequestMethod.GET)
public MyData getMyData() {
return MyDataDefaultService.getData();
}
My Object
public class MyData {
public MyData(final Builder builder) {
videoLink = builder.videoLink;
}
private String videoLink;
public String getVideoLink()
{
return videoLink;
}
public static class Builder
{
private String videoLink = "";
public Builder setVideo(String videoLink)
{
this.videoLink = videoLink;
return this;
}
public MyData build()
{
return new MyData(this);
}
}
#Override
public boolean equals(final Object other) {
return ObjectUtils.equals(this, other);
}
#Override
public int hashCode() {
return ObjectUtils.hashCode(this);
}
#Override
public String toString() {
return ObjectUtils.toString(this);
}
}
The Repository
public classMyServerMyDataRepository implements MyDataRepository{
private finalMyServerMyDataJpaRepository jpaRepository;
private final MyDataConverter MyDataConverter = new MyDataConverter();
#Autowired
publicMyServerMyDataRepository(finalMyServerMyDataJpaRepository jpaRepository) {
this.jpaRepository = Validate.notNull(jpaRepository);
}
#Override
public MyData getData() {
MyDataEntity entity = jpaRepository.findOne((long) 0);
MyData.Builder builder = new MyData.Builder()
.setVideo(entity.getVideoLink());
return builder.build();
}
The DefaultService that gets called by the endpoint
public class MyDataDefaultService {
private static final Logger logger = LoggerFactory.getLogger(NotificationDefaultService.class);
private finalMyServerMyDataRepository repository;
#Autowired
public MyDataDefaultService(MyServerMyDataRepository repository) {
this.repository = Validate.notNull(repository);
}
//Get the data from the server
public MobileData getData()
{
logger.info("Get Mobile Data from the server");
//Get the data from the repository
MobileData mobileData = repository.getData();
return mobileData;
}
}
The Converter
public class MyDataConverter extends AbstractConverter<MyDataEntity, MyData>
{
#Override
public MyData convert(MyDataEntity entity) {
MyData.Builder builder = new MyData.Builder()
.setVideo(entity.getVideoLink());
return builder.build();
}
}
My Entity
#Entity
#Table(name = “myServer”)
public class MyDataEntity extends AbstractEntity{
#Column(name = "video_link", nullable = true)
private String videoLink;
public String getVideoLink() {
return videoLink;
}
public void setVideoLink(final String videoLink) {
this.videoLink = videoLink;
}
}
Thank you for any help with this
Hibernate entity should have default constructor defined and implement Serializable interface as well, assume AbstractEntity matches the requirement. Hibernate won't accept an entity without a primary key so you have to define the one too:
#Entity
#Table(name = “myServer”)
public class MyDataEntity implements Serializable {
#Id
#GeneratedValue
private Long id;
#Column(name = "video_link", nullable = true)
private String videoLink;
public MyDataEntity() {
}
...setters&getters
}
MyData object represents the JSON server response, you can use Jackson annotations to control the result JSON properties:
public class MyDataResponse {
#JsonProperty("video_link")
private String videoLink;
public MyDataResponse() {
}
public MyDataResponse(String videoLink) {
this.videoLink = videoLink;
}
...setters&getters
}
Spring has an awesome project so called Spring Data that provides the JPA repositories, so there's no even the #Repository annotation ever needed:
public class MyDataRepository extends CrudRepository<MyDataEntity, Long> {
}
The Builder class represents the Service layer:
#Service
public class MyDataService {
#Autowired
private MyDataRepository myDataRepository;
public MyDataResponse getMyData(Long id) {
MyDataEntity entity = myDataRepository.findOne(id);
...rest logic, copy necessary data to MyDataResponse
}
}
Then a controller is:
#RestController // #ResponseBody not needed when using like this
public MyDataController {
#Autowired
private MyDataService myDataService;
#RequestMapping("/getMyData") // no need to specify method for GET
public MyDataResponse getMyData(#RequestParam("ID") Long myDataId) {
... validation logic
return myDataService.getMyData(myDataId); // return response
}
}
Now it should work, don't forget to add required dependencies to your classpath.

Handling MethodArgumentNotValidException in Junit testcase?

I am using spring MVC testing: In my test case, I am passing an invalid Bar object(age with zero). The MethodArgumentNotValidException is being thrown, but it is nested inside a NestedServletException. Is there anyway to throw the MethodArgumentNotValidException exception from the controller through an existing/custom HandlerExceptionResolver, so that my current test case checkHit2 passes?
Controller:
#RequestMapping(value="/test", method = RequestMethod.POST, headers="Accept=application/json")
#ResponseBody
public Bar getTables(#Valid #RequestBody Bar id) {
return id;
}
TestCase
#Before
public void setUp() {
mockMvc = standaloneSetup(excelFileUploader).setHandlerExceptionResolvers(new SimpleMappingExceptionResolver()).build();
}
#Test(expected=MethodArgumentNotValidException.class)
public void checkHit2() throws Exception {
Bar b = new Bar(0, "Sfd");
mockMvc.perform(
post("/excel/tablesDetail").contentType(
MediaType.APPLICATION_JSON).content(
TestUtil.convertObjectToJsonBytes(b)));
Bar
public class Bar {
#JsonProperty("age")
#Min(value =1)
private int age;
public Bar(int age, String name) {
super();
this.age = age;
this.name = name;
}
...
}
Junit output
java.lang.Exception: Unexpected exception,
expected<org.springframework.web.bind.MethodArgumentNotValidException> but
was<org.springframework.web.util.NestedServletException>
I had similar issue and I fixed it extending my exception class from NestedServletException. For example:
#RequestMapping(value = "/updateForm/{roleID}", method = RequestMethod.GET)
public String updateForm(#PathVariable Long roleID, Model model, HttpSession session) throws ElementNotFoundException {
Role role = roleService.findOne(roleID);
if (role == null) {
throw new ElementNotFoundException("Role");
}
...
}
And my exception looks like:
public class ElementNotFoundException extends NestedServletException {
private static final long serialVersionUID = 2689075086409560459L;
private String typeElement;
public ElementNotFoundException(String typeElement) {
super(typeElement);
this.typeElement = typeElement;
}
public String getTypeElement() {
return typeElement;
}
}
So my test is:
#Test(expected = ElementNotFoundException.class)
public void updateForm_elementNotFound_Test() throws Exception {
String roleID = "1";
Mockito.when(roleService.findOne(Long.valueOf(roleID))).thenReturn(null);
mockMvc.perform(get("/role/updateForm/" + roleID)).andExpect(status().isOk()).andExpect(view().name("exception/elementNotFound"));
}

Categories

Resources