@Override
  protected ResponseEntity<Object> handleMethodArgumentNotValid(
      MethodArgumentNotValidException ex,
      HttpHeaders headers,
      HttpStatus status,
      WebRequest request) {
    final List<FieldError> fieldErrors = ex.getBindingResult().getFieldErrors();
    final List<ObjectError> globalErrors = ex.getBindingResult().getGlobalErrors();

    StringBuilder errors = new StringBuilder();

    for (FieldError fieldError : fieldErrors) {
      errors
          .append(fieldError.getField())
          .append(": ")
          .append(fieldError.getDefaultMessage())
          .append("\n");
    }

    for (ObjectError globalError : globalErrors) {
      errors
          .append(globalError.getObjectName())
          .append(": ")
          .append(globalError.getDefaultMessage())
          .append("\n");
    }

    return new ResponseEntity<>(errors.toString(), headers, status);
  }
Example #2
0
 public static void setJSONErrorMap(JSONBean<?> json, BindingResult result) {
   List<FieldError> fields = result.getFieldErrors();
   for (FieldError field : fields) {
     System.out.println(field.getField() + ": " + field.getDefaultMessage());
     json.getErrorMap().put(field.getField(), field.getDefaultMessage());
   }
 }
Example #3
0
 public static BaseResponse createResponse(HttpStatus status, BindingResult result) {
   BaseResponse response = new BaseResponse();
   if (result.hasErrors()) {
     response.setError(true);
     response.setHttpErrorCode(status.value());
     /* create an array of total error count */
     ArrayList<ErrorDTO> errors = new ArrayList<ErrorDTO>(result.getErrorCount());
     /* append all field errors */
     for (FieldError err : result.getFieldErrors()) {
       System.out.println(
           "I got field error for: "
               + err.getField()
               + ", message: "
               + err.getDefaultMessage()
               + ", code: "
               + err.getCode());
       ErrorDTO dto = new ErrorDTO(err.getField(), err.getCode(), err.getDefaultMessage());
       errors.add(dto);
     }
     /* append global errors now */
     for (ObjectError err : result.getGlobalErrors()) {
       System.out.println(
           "I got global error for: "
               + err.getObjectName()
               + ", message: "
               + err.getDefaultMessage()
               + ", code: "
               + err.getCode());
       ErrorDTO dto = new ErrorDTO(err.getObjectName(), err.getCode(), err.getDefaultMessage());
       errors.add(dto);
     }
     response.setErrors(errors);
   }
   return response;
 }
  @ResponseBody
  @RequestMapping(value = "/edit", method = RequestMethod.POST)
  public ImmutableMap<String, Object> linkEdit(@Valid Link link, BindingResult bindingResult) {
    if (bindingResult.hasErrors()) {
      Map<String, Object> errorMessage = Maps.newHashMap();
      errorMessage.put("status", 0);
      List<FieldError> fes = bindingResult.getFieldErrors();
      for (FieldError fe : fes) {
        errorMessage.put(fe.getField(), fe.getDefaultMessage());
      }
      return ImmutableMap.<String, Object>builder().putAll(errorMessage).build();
    }

    if (link.getLinkId() == null || link.getLinkId() == 0) {
      Link result = linkService.save(link);
      if (result == null || result.getLinkId() == null || result.getLinkId() == 0) {
        LOGGER.warn("内容链接失败,链接{}", result);
        return ImmutableMap.<String, Object>of(
            "status", "0", "message", getMessage("link.addfailed.message"));
      }
      LOGGER.info("内容添加成功,链接ID{}", result.getLinkId());
      return ImmutableMap.<String, Object>of(
          "status", "1", "message", getMessage("link.addsuccess.message"));
    }
    try {
      linkService.save(link);
    } catch (Exception e) {
      LOGGER.error("链接修改失败,{}", e);
      return ImmutableMap.<String, Object>of(
          "status", "0", "message", getMessage("link.updatefailed.message"));
    }
    LOGGER.info("链接添加成功,{}", link);
    return ImmutableMap.<String, Object>of(
        "status", "1", "message", getMessage("link.updatesuccess.message"));
  }
  /**
   * méthode pour gérer les problèmes de validation de l'objet resource
   *
   * @param exception
   * @param response
   * @return
   */
  @ExceptionHandler
  @ResponseBody
  public Map<String, Object> handleException(Exception exception, HttpServletResponse response) {

    LOGGER.error("Exception : ", exception);

    Map<String, Object> mapErrorMessage = new HashMap<>();
    if (exception instanceof MethodArgumentNotValidException) {

      BindingResult result = ((MethodArgumentNotValidException) exception).getBindingResult();
      List<FieldError> listFieldErrors = result.getFieldErrors();
      for (FieldError fieldError : listFieldErrors) {
        mapErrorMessage.put(fieldError.getField(), fieldError.getDefaultMessage());
      }
      response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
    }

    if (exception instanceof AccessDeniedException) {

      mapErrorMessage.put("Error : ", exception.getMessage());
      response.setStatus(HttpServletResponse.SC_FORBIDDEN);
    } else if (exception instanceof ValidationException
        || exception instanceof HttpMessageNotReadableException
        || exception instanceof DataAccessException
        || exception instanceof MongoException
        || exception instanceof SocketTimeoutException
        || exception instanceof RuntimeException) {

      mapErrorMessage.put("Error : ", exception.getMessage());
      response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
    }

    LOGGER.error(mapErrorMessage.toString(), exception);
    return mapErrorMessage;
  }
  @RequestMapping(value = "/bd_quick_reply", method = RequestMethod.PUT)
  @ResponseBody
  public Map<String, Object> update(
      @Valid QuickReply quickReply, Errors errors, Map<String, Object> map) {
    Map<String, Object> result = new HashMap<>();

    if (errors.getErrorCount() > 0) {
      result.put("result", "error");
      for (FieldError err : errors.getFieldErrors()) {
        map.put("err_" + err.getField(), err.getDefaultMessage());
      }
      return result;
    }

    try {
      quickReplyService.update(quickReply);
      result.put("result", "success");
    } catch (BusinessException e) {
      log.error(e.getMessage(), e);
      result.put("result", "error");
      result.put("errorMsg", e.getMessage());
    }

    return result;
  }
 @Test
 public void shouldAddErrorWhenEmptySourceIds() throws Exception {
   InvitationSentRecord record = InvitationSentRecord.toInvitationSentRecord("SLOTS", "IOS", "");
   Errors errors = new BeanPropertyBindingResult(record, "record");
   validator.validate(record, errors);
   FieldError fieldError = errors.getFieldError("sourceIds");
   assertEquals("sourceIds must be present", fieldError.getDefaultMessage());
   assertEquals("empty", fieldError.getCode());
 }
Example #8
0
 public static List<KeyValuePair<String, String>> listErrors(BindingResult binding) {
   List<KeyValuePair<String, String>> errors = new ArrayList<KeyValuePair<String, String>>();
   KeyValuePair<String, String> kvp;
   for (FieldError fe : binding.getFieldErrors()) {
     kvp = new KeyValuePair<String, String>(fe.getField(), fe.getDefaultMessage());
     errors.add(kvp);
   }
   return errors;
 }
  @ExceptionHandler(MethodArgumentNotValidException.class)
  @ResponseStatus(HttpStatus.BAD_REQUEST)
  @ResponseBody
  public ErrorTester noRequestHandlerFoundExceptionHandler(MethodArgumentNotValidException e) {

    BindingResult result = e.getBindingResult();
    FieldError error = result.getFieldError();

    return new ErrorTester("There is error " + error.getDefaultMessage());
  }
 @Test
 public void shouldAddErrorWhenNullPlatform() throws Exception {
   InvitationSentRecord record =
       InvitationSentRecord.toInvitationSentRecord("SLOTS", null, "*****@*****.**");
   Errors errors = new BeanPropertyBindingResult(record, "record");
   validator.validate(record, errors);
   FieldError fieldError = errors.getFieldError("platform");
   assertEquals("platform must be present", fieldError.getDefaultMessage());
   assertEquals("empty", fieldError.getCode());
 }
 @Test
 public void shouldAddErrorWhenUnknownGame() throws Exception {
   InvitationSentRecord record =
       InvitationSentRecord.toInvitationSentRecord("BLACKJACK", "IOS", "*****@*****.**");
   Errors errors = new BeanPropertyBindingResult(record, "record");
   validator.validate(record, errors);
   FieldError fieldError = errors.getFieldError("gameType");
   assertEquals("gameType is not supported", fieldError.getDefaultMessage());
   assertEquals("unsupported", fieldError.getCode());
 }
 @Test
 public void shouldAddErrorWhenSourceIDIsBlank() {
   InvitationSentRecord record =
       InvitationSentRecord.toInvitationSentRecord("SLOTS", "IOS", ",1002222223");
   Errors errors = new BeanPropertyBindingResult(record, "record");
   validator.validate(record, errors);
   FieldError fieldError = errors.getFieldError("sourceIds");
   assertEquals("sourceIds cannot be blank", fieldError.getDefaultMessage());
   assertEquals("nullOrBlankSourceId", fieldError.getCode());
 }
 @Test
 public void shouldAddErrorWhenInvalidPlatform() throws Exception {
   InvitationSentRecord record =
       InvitationSentRecord.toInvitationSentRecord("SLOTS", "PLAYSTATION", "*****@*****.**");
   Errors errors = new BeanPropertyBindingResult(record, "record");
   validator.validate(record, errors);
   FieldError fieldError = errors.getFieldError("platform");
   assertEquals("platform is not supported", fieldError.getDefaultMessage());
   assertEquals("unsupported", fieldError.getCode());
 }
 private MessageDTO processFieldError(FieldError error) {
   MessageDTO message = null;
   if (error != null) {
     Locale currentLocale = LocaleContextHolder.getLocale();
     String msg = msgSource.getMessage(error.getDefaultMessage(), null, currentLocale);
     ClientException clientException = new ClientException(RestErrorCodes.ERR_001, msg);
     message = new MessageDTO(MessageType.ERROR, clientException);
   }
   return message;
 }
  @ExceptionHandler(MethodArgumentNotValidException.class)
  @ResponseStatus(HttpStatus.BAD_REQUEST)
  public Map<String, String> handleValidationError(MethodArgumentNotValidException ex) {
    Map<String, String> fieldErrorMap = new HashMap<>();

    BindingResult result = ex.getBindingResult();
    List<FieldError> fieldErrors = result.getFieldErrors();
    for (FieldError fieldError : fieldErrors) {
      fieldErrorMap.put(fieldError.getField(), fieldError.getDefaultMessage());
    }

    return fieldErrorMap;
  }
 /** Exception to be thrown when validation on an argument annotated with @Valid fails. */
 @ExceptionHandler(MethodArgumentNotValidException.class)
 public ResponseEntity<Map<String, Object>> handleMethodArgumentNotValidException(
     MethodArgumentNotValidException errors) {
   Map<String, Object> errorMap = new HashMap<String, Object>();
   errorMap.put("hasErrors", "true");
   errorMap.put("developerMessage", "There are validation issues, please provide valid inputs");
   errorMap.put("userMessage", "Please provide valid inputs");
   errorMap.put("moreInfo", errors.getMessage());
   errorMap.put("errorCode", HttpStatus.BAD_REQUEST);
   errors.printStackTrace();
   for (FieldError error : errors.getBindingResult().getFieldErrors()) {
     errorMap.put(error.getField(), error.getDefaultMessage());
   }
   return new ResponseEntity<Map<String, Object>>(errorMap, HttpStatus.BAD_REQUEST);
 }
Example #17
0
  /**
   * Builds an error message from the web parameters binding result if there're errors.
   *
   * @param bindingResult
   * @return
   */
  protected final String errorFromBindingResult(BindingResult bindingResult) {
    StringBuilder sb = new StringBuilder();
    for (FieldError fe : bindingResult.getFieldErrors()) {
      Object rejectedVal = fe.getRejectedValue();
      if (rejectedVal instanceof Object[]) {
        if (((Object[]) rejectedVal).length > 0) {
          rejectedVal = Arrays.toString((Object[]) rejectedVal);
        } else {
          rejectedVal = "empty array";
        }
      }
      sb.append(fe.getField() + " was '" + rejectedVal + "'; " + fe.getDefaultMessage() + ". ");
    }

    return sb.toString();
  }
Example #18
0
  /**
   * Example Usage:
   *
   * <pre>
   * &#064;Controller
   * class UserController {
   * 	&#064;RequestMapping(value = &quot;/userAjaxCheck.json&quot;, method = RequestMethod.POST)
   * 	public @ResponseBody ValidationResponse processFormAjaxJson(Model model,
   * 			&#064;ModelAttribute(value = &quot;user&quot;) @Valid User user,
   * 			BindingResult result) {
   * 		return AjaxValidationEngine.process(result);
   * 	}
   * }
   * </pre>
   *
   * @param result
   * @return
   */
  public static ValidationResponse process(BindingResult result) {
    ValidationResponse res = new ValidationResponse();
    if (!result.hasErrors()) {
      res.setStatus("SUCCESS");
    } else {
      res.setStatus("FAIL");
      List<FieldError> allErrors = result.getFieldErrors();
      List<ErrorMessage> errorMesages = new ArrayList<ErrorMessage>();
      for (FieldError objectError : allErrors) {
        errorMesages.add(new ErrorMessage(objectError.getField(), objectError.getDefaultMessage()));
      }
      res.setErrorMessageList(errorMesages);
    }

    return res;
  }
 @ExceptionHandler(InvalidRequestException.class)
 public ResponseEntity<Object> handleInvalidRequest(RuntimeException e, WebRequest request) {
   InvalidRequestException ire = (InvalidRequestException) e;
   List<FieldErrorResource> fieldErrorResources = new ArrayList<>();
   List<FieldError> fieldErrors = ire.getErrors().getFieldErrors();
   for (FieldError fieldError : fieldErrors) {
     FieldErrorResource fieldErrorResource = new FieldErrorResource();
     fieldErrorResource.setResource(fieldError.getObjectName());
     fieldErrorResource.setField(fieldError.getField());
     fieldErrorResource.setCode(fieldError.getCode());
     fieldErrorResource.setMessage(fieldError.getDefaultMessage());
     fieldErrorResources.add(fieldErrorResource);
   }
   ErrorResource error = errorResource("InvalidRequest", ire.getMessage());
   error.setFieldErrors(fieldErrorResources);
   return handleExceptionInternal(
       e, error, getHeaders(), HttpStatus.UNPROCESSABLE_ENTITY, request);
 }
Example #20
0
 @RequestMapping("/handleupdate")
 public ModelAndView handleUpdate(@Valid User user, BindingResult result) {
   ModelAndView mv = new ModelAndView();
   if (result.hasFieldErrors()) {
     List<FieldError> list1 = result.getFieldErrors();
     List<String> list = new LinkedList<String>();
     Iterator<FieldError> it = list1.iterator();
     while (it.hasNext()) {
       FieldError f = (FieldError) it.next();
       String s = f.getDefaultMessage();
       list.add(s);
     }
     mv.addObject("errors", list);
     mv.setViewName("error");
     return mv;
   } else {
     service.updateUser(user);
     mv.setView(new RedirectView("/"));
     return mv;
   }
 }
Example #21
0
  /**
   * Binds data to this form - that is, handles form submission.
   *
   * @param data data to submit
   * @return a copy of this form filled with the new data
   */
  public Form<T> bind(Map<String, String> data, String... allowedFields) {

    DataBinder dataBinder = null;
    Map<String, String> objectData = data;
    if (rootName == null) {
      dataBinder = new DataBinder(blankInstance());
    } else {
      dataBinder = new DataBinder(blankInstance(), rootName);
      objectData = new HashMap<String, String>();
      for (String key : data.keySet()) {
        if (key.startsWith(rootName + ".")) {
          objectData.put(key.substring(rootName.length() + 1), data.get(key));
        }
      }
    }
    if (allowedFields.length > 0) {
      dataBinder.setAllowedFields(allowedFields);
    }
    SpringValidatorAdapter validator =
        new SpringValidatorAdapter(play.data.validation.Validation.getValidator());
    dataBinder.setValidator(validator);
    dataBinder.setConversionService(play.data.format.Formatters.conversion);
    dataBinder.setAutoGrowNestedPaths(true);
    dataBinder.bind(new MutablePropertyValues(objectData));
    Set<ConstraintViolation<Object>> validationErrors;
    if (groups != null) {
      validationErrors = validator.validate(dataBinder.getTarget(), groups);
    } else {
      validationErrors = validator.validate(dataBinder.getTarget());
    }

    BindingResult result = dataBinder.getBindingResult();

    for (ConstraintViolation<Object> violation : validationErrors) {
      String field = violation.getPropertyPath().toString();
      FieldError fieldError = result.getFieldError(field);
      if (fieldError == null || !fieldError.isBindingFailure()) {
        try {
          result.rejectValue(
              field,
              violation.getConstraintDescriptor().getAnnotation().annotationType().getSimpleName(),
              getArgumentsForConstraint(
                  result.getObjectName(), field, violation.getConstraintDescriptor()),
              violation.getMessage());
        } catch (NotReadablePropertyException ex) {
          throw new IllegalStateException(
              "JSR-303 validated property '"
                  + field
                  + "' does not have a corresponding accessor for data binding - "
                  + "check your DataBinder's configuration (bean property versus direct field access)",
              ex);
        }
      }
    }

    if (result.hasErrors()) {
      Map<String, List<ValidationError>> errors = new HashMap<String, List<ValidationError>>();
      for (FieldError error : result.getFieldErrors()) {
        String key = error.getObjectName() + "." + error.getField();
        if (key.startsWith("target.") && rootName == null) {
          key = key.substring(7);
        }
        List<Object> arguments = new ArrayList<Object>();
        for (Object arg : error.getArguments()) {
          if (!(arg
              instanceof org.springframework.context.support.DefaultMessageSourceResolvable)) {
            arguments.add(arg);
          }
        }
        if (!errors.containsKey(key)) {
          errors.put(key, new ArrayList<ValidationError>());
        }
        errors
            .get(key)
            .add(
                new ValidationError(
                    key,
                    error.isBindingFailure() ? "error.invalid" : error.getDefaultMessage(),
                    arguments));
      }
      return new Form(rootName, backedType, data, errors, None(), groups);
    } else {
      Object globalError = null;
      if (result.getTarget() != null) {
        try {
          java.lang.reflect.Method v = result.getTarget().getClass().getMethod("validate");
          globalError = v.invoke(result.getTarget());
        } catch (NoSuchMethodException e) {
        } catch (Throwable e) {
          throw new RuntimeException(e);
        }
      }
      if (globalError != null) {
        Map<String, List<ValidationError>> errors = new HashMap<String, List<ValidationError>>();
        if (globalError instanceof String) {
          errors.put("", new ArrayList<ValidationError>());
          errors.get("").add(new ValidationError("", (String) globalError, new ArrayList()));
        } else if (globalError instanceof List) {
          errors.put("", (List<ValidationError>) globalError);
        } else if (globalError instanceof Map) {
          errors = (Map<String, List<ValidationError>>) globalError;
        }
        return new Form(rootName, backedType, data, errors, None(), groups);
      }
      return new Form(
          rootName,
          backedType,
          new HashMap<String, String>(data),
          new HashMap<String, List<ValidationError>>(errors),
          Some((T) result.getTarget()),
          groups);
    }
  }
 private FieldError mockFieldErrorWithMessage(String message) {
   FieldError fieldError = mock(FieldError.class);
   when(fieldError.getDefaultMessage()).thenReturn(message);
   return fieldError;
 }
Example #23
0
  /**
   * Binds data to this form - that is, handles form submission.
   *
   * @param data data to submit
   * @return a copy of this form filled with the new data
   */
  @SuppressWarnings("unchecked")
  public Form<T> bind(Map<String, String> data, String... allowedFields) {

    DataBinder dataBinder;
    Map<String, String> objectData = data;
    if (rootName == null) {
      dataBinder = new DataBinder(blankInstance());
    } else {
      dataBinder = new DataBinder(blankInstance(), rootName);
      objectData = new HashMap<>();
      for (String key : data.keySet()) {
        if (key.startsWith(rootName + ".")) {
          objectData.put(key.substring(rootName.length() + 1), data.get(key));
        }
      }
    }
    if (allowedFields.length > 0) {
      dataBinder.setAllowedFields(allowedFields);
    }
    SpringValidatorAdapter validator =
        new SpringValidatorAdapter(play.data.validation.Validation.getValidator());
    dataBinder.setValidator(validator);
    dataBinder.setConversionService(formatters.conversion);
    dataBinder.setAutoGrowNestedPaths(true);
    final Map<String, String> objectDataFinal = objectData;
    withRequestLocale(
        () -> {
          dataBinder.bind(new MutablePropertyValues(objectDataFinal));
          return null;
        });
    Set<ConstraintViolation<Object>> validationErrors;
    if (groups != null) {
      validationErrors = validator.validate(dataBinder.getTarget(), groups);
    } else {
      validationErrors = validator.validate(dataBinder.getTarget());
    }

    BindingResult result = dataBinder.getBindingResult();

    for (ConstraintViolation<Object> violation : validationErrors) {
      String field = violation.getPropertyPath().toString();
      FieldError fieldError = result.getFieldError(field);
      if (fieldError == null || !fieldError.isBindingFailure()) {
        try {
          result.rejectValue(
              field,
              violation.getConstraintDescriptor().getAnnotation().annotationType().getSimpleName(),
              getArgumentsForConstraint(
                  result.getObjectName(), field, violation.getConstraintDescriptor()),
              getMessageForConstraintViolation(violation));
        } catch (NotReadablePropertyException ex) {
          throw new IllegalStateException(
              "JSR-303 validated property '"
                  + field
                  + "' does not have a corresponding accessor for data binding - "
                  + "check your DataBinder's configuration (bean property versus direct field access)",
              ex);
        }
      }
    }

    if (result.hasErrors() || result.getGlobalErrorCount() > 0) {
      Map<String, List<ValidationError>> errors = new HashMap<>();
      for (FieldError error : result.getFieldErrors()) {
        String key = error.getObjectName() + "." + error.getField();
        if (key.startsWith("target.") && rootName == null) {
          key = key.substring(7);
        }
        if (!errors.containsKey(key)) {
          errors.put(key, new ArrayList<>());
        }

        ValidationError validationError;
        if (error.isBindingFailure()) {
          ImmutableList.Builder<String> builder = ImmutableList.builder();
          Optional<Messages> msgs =
              Optional.of(Http.Context.current.get()).map(c -> messagesApi.preferred(c.request()));
          for (String code : error.getCodes()) {
            code = code.replace("typeMismatch", "error.invalid");
            if (!msgs.isPresent() || msgs.get().isDefinedAt(code)) {
              builder.add(code);
            }
          }
          validationError =
              new ValidationError(
                  key, builder.build().reverse(), convertErrorArguments(error.getArguments()));
        } else {
          validationError =
              new ValidationError(
                  key, error.getDefaultMessage(), convertErrorArguments(error.getArguments()));
        }
        errors.get(key).add(validationError);
      }

      List<ValidationError> globalErrors = new ArrayList<>();

      for (ObjectError error : result.getGlobalErrors()) {
        globalErrors.add(
            new ValidationError(
                "", error.getDefaultMessage(), convertErrorArguments(error.getArguments())));
      }

      if (!globalErrors.isEmpty()) {
        errors.put("", globalErrors);
      }

      return new Form(
          rootName, backedType, data, errors, Optional.empty(), groups, messagesApi, formatters);
    } else {
      Object globalError = null;
      if (result.getTarget() != null) {
        try {
          java.lang.reflect.Method v = result.getTarget().getClass().getMethod("validate");
          globalError = v.invoke(result.getTarget());
        } catch (NoSuchMethodException e) {
          // do nothing
        } catch (Throwable e) {
          throw new RuntimeException(e);
        }
      }
      if (globalError != null) {
        Map<String, List<ValidationError>> errors = new HashMap<>();
        if (globalError instanceof String) {
          errors.put("", new ArrayList<>());
          errors.get("").add(new ValidationError("", (String) globalError, new ArrayList()));
        } else if (globalError instanceof List) {
          for (ValidationError error : (List<ValidationError>) globalError) {
            List<ValidationError> errorsForKey = errors.get(error.key());
            if (errorsForKey == null) {
              errors.put(error.key(), errorsForKey = new ArrayList<>());
            }
            errorsForKey.add(error);
          }
        } else if (globalError instanceof Map) {
          errors = (Map<String, List<ValidationError>>) globalError;
        }
        return new Form(
            rootName, backedType, data, errors, Optional.empty(), groups, messagesApi, formatters);
      }
      return new Form(
          rootName,
          backedType,
          new HashMap<>(data),
          new HashMap<>(errors),
          Optional.ofNullable((T) result.getTarget()),
          groups,
          messagesApi,
          formatters);
    }
  }