/** * This Source Code Form is subject to the terms of the Mozilla Public License, * v. 2.0. If a copy of the MPL was not distributed with this file, You can * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under * the terms of the Healthcare Disclaimer located at http://openmrs.org/license. * * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS * graphic logo is a trademark of OpenMRS Inc. */ package org.openmrs.module.webservices.validation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.LinkedHashSet; import java.util.Set; import org.apache.commons.lang.StringUtils; import org.openmrs.api.APIException; import org.openmrs.api.AdministrationService; import org.openmrs.api.context.Context; import org.springframework.validation.BindException; import org.springframework.validation.Errors; import org.springframework.validation.FieldError; import org.springframework.validation.ObjectError; /** * This is just a copy of the 1.9.x core ValidateUtil method, *except* that if a validation failure * occurs, then it returns a ValidationException with the Spring Errors object included within in * (see RESTWS-422) This change will also been made to core (TRUNK-4296). Once REST-WS only supports * versions of core that have this change, this class (and ValidationException) can be removed, and * we will not have to explicitly call the "validate" within the DelegatingCrudResource, as we can * rely on the underlying API validation to do the right thing, and return a ValidationException * with Errors which we can trap in the BaseRestController */ public class ValidateUtil { /** * Test the given object against all validators that are registered as compatible with the * object class * * @param obj the object to validate * @throws ValidationException thrown if a binding exception occurs * @should throw ValidationException if errors occur during validation */ public static void validate(Object obj) throws ValidationException { Errors errors = new BindException(obj, ""); AdministrationService administrationService = Context.getAdministrationService(); try { // using refection here for compatibility with OpenMRS 1.8,x, which does not have this method Method validate = AdministrationService.class.getMethod("validate", Object.class, Errors.class); validate.invoke(administrationService, obj, errors); } catch (NoSuchMethodException ex) { // not running OpenMRS 1.9 or higher, so just skip this validation return; } catch (InvocationTargetException ex) { throw new APIException("Unable to invoke administrationService.validate(Object, Errors) via reflection", ex); } catch (IllegalAccessException ex) { throw new APIException("Unable to invoke administrationService.validate(Object, Errors) via reflection", ex); } if (errors.hasErrors()) { throw new ValidationException(generateExceptionMessage(obj, errors), errors); } } private static String generateExceptionMessage(Object obj, Errors errors) { Set<String> uniqueErrorMessages = new LinkedHashSet<String>(); for (Object objerr : errors.getAllErrors()) { ObjectError error = (ObjectError) objerr; String message = Context.getMessageSourceService().getMessage(error.getCode()); if (error instanceof FieldError) { message = ((FieldError) error).getField() + ": " + message; } uniqueErrorMessages.add(message); } String exceptionMessage = "'" + obj + "' failed to validate with reason: "; exceptionMessage += StringUtils.join(uniqueErrorMessages, ", "); return exceptionMessage; } }