blob: 060fcee0bebb167bdad5d8204964a7ccdb2c9f2f [file] [log] [blame]
/*
* Copyright (c) 2015, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Marcel Valovy - initial implementation
package org.eclipse.persistence.testing.jaxb.beanvalidation;
import org.eclipse.persistence.exceptions.BeanValidationException;
import org.eclipse.persistence.jaxb.ConstraintViolationWrapper;
import org.eclipse.persistence.jaxb.JAXBContext;
import org.eclipse.persistence.jaxb.JAXBContextFactory;
import org.eclipse.persistence.jaxb.JAXBMarshaller;
import org.eclipse.persistence.testing.jaxb.beanvalidation.special.ExternallyConstrainedEmployee;
import org.eclipse.persistence.testing.jaxb.beanvalidation.special.ExternallyConstrainedEmployee2;
import org.junit.After;
import org.junit.Before;
import jakarta.validation.Validation;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.Set;
/**
*
* @author Marcel Valovy - marcel.valovy@oracle.com
*/
public class ValidationXMLTestCase extends junit.framework.TestCase {
private static final String NOT_NULL_MESSAGE = "{jakarta.validation.constraints.NotNull.message}";
private static final String MIN_MESSAGE = "{jakarta.validation.constraints.Min.message}";
private static final String MOXY_JAXBCONTEXT_FACTORY = JAXBContextFactory.class.getName();
private static final String SYSTEM_PROPERTY_JAXBCONTEXT = "jakarta.xml.bind.JAXBContext";
private static final String VALIDATION_XML = "META-INF/validation.xml";
private static final String CONSTRAINTS_XML = "META-INF/validation/constraints.xml";
private static final String CONSTRAINTS2_XML = "META-INF/validation/constraints2.xml";
private static final String VALIDATION_XML_PATH = "org/eclipse/persistence/testing/jaxb/beanvalidation/validation.xml";
private static final String CONSTRAINTS_XML_PATH = "org/eclipse/persistence/testing/jaxb/beanvalidation/constraints.xml";
private static final String CONSTRAINTS2_XML_PATH = "org/eclipse/persistence/testing/jaxb/beanvalidation/constraints2.xml";
private static final boolean DEBUG = false;
private ClassLoader classLoader;
private Thread currentThread = Thread.currentThread();
private static final class ValidationClassLoader extends ClassLoader {
ValidationClassLoader(ClassLoader parent) {
super(parent);
}
@Override
public URL getResource(String name) {
if (name != null) {
switch (name) {
case VALIDATION_XML:
return getParent().getResource(VALIDATION_XML_PATH);
case CONSTRAINTS_XML:
return getParent().getResource(CONSTRAINTS_XML_PATH);
case CONSTRAINTS2_XML:
return getParent().getResource(CONSTRAINTS2_XML_PATH);
}
}
return super.getResource(name);
}
}
/**
* Tests fix for endless invocation loop between
* unmarshaller - validator - unmarshaller.
* File {@link #VALIDATION_XML} must be present on classpath.
*/
public void testEndlessLoopInvocations() throws Exception {
final String previous = System.getProperty(SYSTEM_PROPERTY_JAXBCONTEXT);
try {
System.setProperty(SYSTEM_PROPERTY_JAXBCONTEXT, MOXY_JAXBCONTEXT_FACTORY);
assertEquals(MOXY_JAXBCONTEXT_FACTORY, System.getProperty(SYSTEM_PROPERTY_JAXBCONTEXT));
if (DEBUG) System.out.println("System property \"" + SYSTEM_PROPERTY_JAXBCONTEXT +
"\"'s value has been set to " + System.getProperty(SYSTEM_PROPERTY_JAXBCONTEXT));
Validation.buildDefaultValidatorFactory();
} finally {
final String clearedProperty = previous != null
? System.setProperty(SYSTEM_PROPERTY_JAXBCONTEXT, previous)
: System.clearProperty(SYSTEM_PROPERTY_JAXBCONTEXT);
assertEquals(MOXY_JAXBCONTEXT_FACTORY, clearedProperty);
if (DEBUG) System.out.println("System property \"" + SYSTEM_PROPERTY_JAXBCONTEXT
+ "\"'s value has been cleared,"
+ "unless it previously was set, in which case it's original value has been restored.");
}
}
/**
* Tests that we do not skip validation on classes that are constrained through validation.xml.
*/
public void testExternalConstraints() throws Exception {
JAXBMarshaller marshaller = (JAXBMarshaller) JAXBContextFactory.createContext(new
Class[]{ExternallyConstrainedEmployee.class, ExternallyConstrainedEmployee2.class},
null).createMarshaller();
ExternallyConstrainedEmployee employee = new ExternallyConstrainedEmployee().withId(null).withAge(15);
ExternallyConstrainedEmployee2 employee2 = new ExternallyConstrainedEmployee2().withId(null).withAge(15);
try {
marshaller.marshal(employee, new StringWriter());
} catch (BeanValidationException ignored) {
}
Set<ConstraintViolationWrapper<Object>> violations = marshaller.getConstraintViolations();
try {
marshaller.marshal(employee2, new StringWriter());
} catch (BeanValidationException ignored) {
}
violations.addAll(marshaller.getConstraintViolations());
assertFalse("Some constraints were not validated, even though they should have been.", violations.isEmpty());
int i = 0;
for (ConstraintViolationWrapper<Object> cv : violations) {
if (NOT_NULL_MESSAGE.equals(cv.getMessageTemplate())) i += 0b1000;
if (MIN_MESSAGE.equals(cv.getMessageTemplate())) i += 0b0001;
}
assertTrue(i == 0b1001);
}
@Override
@Before
public void setUp() throws Exception {
classLoader = new ValidationClassLoader(currentThread.getContextClassLoader());
currentThread.setContextClassLoader(classLoader);
resetBeanValidation();
}
private void resetBeanValidation() throws Exception {
Field beanValidationHelper = JAXBContext.class.getDeclaredField("beanValidationHelper");
Field beanValidationPresent = JAXBContext.class.getDeclaredField("beanValidationPresent");
beanValidationHelper.setAccessible(true);
beanValidationPresent.setAccessible(true);
beanValidationHelper.set(JAXBContext.class, null);
beanValidationPresent.set(JAXBContext.class, null);
beanValidationHelper.setAccessible(false);
beanValidationPresent.setAccessible(false);
}
@Override
@After
public void tearDown() throws Exception {
currentThread.setContextClassLoader(classLoader.getParent());
}
}