OPENJPA-1068 Modified exception translator to translate wrapped validation exceptions. EM operations now throw correct validation exceptions.

git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@790700 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Jeremy Bauer 2009-07-02 18:21:26 +00:00
parent c2afd1cefd
commit c24bc1d75c
6 changed files with 114 additions and 10 deletions

View File

@ -15,6 +15,7 @@ package org.apache.openjpa.integration.validation;
import javax.persistence.Query;
import javax.persistence.ValidationMode;
import javax.validation.ConstraintViolationException;
import org.apache.openjpa.conf.OpenJPAConfiguration;
import org.apache.openjpa.lib.log.Log;
@ -102,7 +103,7 @@ public class TestConstraints extends SingleEMFTestCase {
em.getTransaction().commit();
getLog().trace("testNullUpdateConstraint() Part 2 of 2 failed");
fail("Expected a Validation exception");
} catch (Exception e) {
} catch (ConstraintViolationException e) {
// expected
getLog().trace("Caught expected exception = " + e);
getLog().trace("testNullUpdateConstraint() Part 2 of 2 passed");
@ -153,6 +154,9 @@ public class TestConstraints extends SingleEMFTestCase {
if ((em != null) && em.isOpen()) {
em.close();
}
if ((emf != null) && emf.isOpen()) {
emf.close();
}
}
// Part 2 - Verify delete using default group does not cause Validation
@ -186,6 +190,9 @@ public class TestConstraints extends SingleEMFTestCase {
em.getTransaction().rollback();
em.close();
}
if ((emf != null) && emf.isOpen()) {
emf.close();
}
}
}
@ -225,6 +232,9 @@ public class TestConstraints extends SingleEMFTestCase {
if ((em != null) && em.isOpen()) {
em.close();
}
if ((emf != null) && emf.isOpen()) {
emf.close();
}
}
}
@ -251,7 +261,7 @@ public class TestConstraints extends SingleEMFTestCase {
em.getTransaction().commit();
getLog().trace("testNullConstraint() failed");
fail("Expected a Validation exception");
} catch (Exception e) {
} catch (ConstraintViolationException e) {
// expected
getLog().trace("Caught expected exception = " + e);
getLog().trace("testNullConstraint() passed");
@ -285,7 +295,7 @@ public class TestConstraints extends SingleEMFTestCase {
em.getTransaction().commit();
getLog().trace("testNotNullConstraint() failed");
fail("Expected a Validation exception");
} catch (Exception e) {
} catch (ConstraintViolationException e) {
// expected
getLog().trace("Caught expected exception = " + e);
getLog().trace("testNotNullConstraint() passed");
@ -351,7 +361,7 @@ public class TestConstraints extends SingleEMFTestCase {
em.getTransaction().commit();
getLog().trace("testAssertTrueConstraint() failed");
fail("Expected a Validation exception");
} catch (Exception e) {
} catch (ConstraintViolationException e) {
// expected
getLog().trace("Caught expected exception = " + e);
getLog().trace("testAssertTrueConstraint() passed");
@ -385,7 +395,7 @@ public class TestConstraints extends SingleEMFTestCase {
em.getTransaction().commit();
getLog().trace("testAssertFalseConstraint() failed");
fail("Expected a Validation exception");
} catch (Exception e) {
} catch (ConstraintViolationException e) {
// expected
getLog().trace("Caught expected exception = " + e);
getLog().trace("testAssertFalseConstraint() passed");

View File

@ -33,6 +33,7 @@ public interface ExceptionInfo {
public static final int UNSUPPORTED = 3;
public static final int USER = 4;
public static final int WRAPPED = 5;
public static final int UNAVAILABLE = 6;
/**

View File

@ -0,0 +1,44 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.openjpa.validation;
import org.apache.openjpa.util.OpenJPAException;
@SuppressWarnings("serial")
public class ValidationUnavailableException extends OpenJPAException {
public ValidationUnavailableException(String msg) {
super(msg);
}
public ValidationUnavailableException(String msg, RuntimeException e) {
super(msg, e);
}
public ValidationUnavailableException(String msg, RuntimeException e,
boolean fatal) {
super(msg, e);
setFatal(fatal);
}
@Override
public int getType() {
return UNAVAILABLE;
}
}

View File

@ -72,10 +72,12 @@ import org.apache.openjpa.meta.FieldMetaData;
import org.apache.openjpa.meta.QueryMetaData;
import org.apache.openjpa.meta.SequenceMetaData;
import org.apache.openjpa.persistence.criteria.CriteriaBuilder;
import org.apache.openjpa.persistence.validation.ValidationUtils;
import org.apache.openjpa.util.Exceptions;
import org.apache.openjpa.util.ImplHelper;
import org.apache.openjpa.util.RuntimeExceptionTranslator;
import org.apache.openjpa.util.UserException;
import org.apache.openjpa.util.WrappedException;
/**
* Implementation of {@link EntityManager} interface.
@ -552,6 +554,12 @@ public class EntityManagerImpl
} catch (IllegalStateException e) {
throw e;
} catch (Exception e) {
// Per JPA 2.0 spec, if the exception was due to a JSR-303
// constraint violation, the ConstraintViolationException should be
// thrown. Since JSR-303 is optional, the cast to RuntimeException
// prevents the introduction of a runtime dependency on the BV API.
if (ValidationUtils.isConstraintViolationException(e))
throw (RuntimeException)e;
// RollbackExceptions are special and aren't handled by the
// normal exception translator, since the spec says they
// should be thrown whenever the commit fails for any reason at

View File

@ -33,6 +33,7 @@ import org.apache.openjpa.util.QueryException;
import org.apache.openjpa.util.RuntimeExceptionTranslator;
import org.apache.openjpa.util.StoreException;
import org.apache.openjpa.util.UserException;
import org.apache.openjpa.util.WrappedException;
/**
* Converts from OpenJPA to persistence exception types.
@ -138,6 +139,8 @@ public class PersistenceExceptions
return translateStoreException(ke);
case OpenJPAException.USER:
return translateUserException(ke);
case OpenJPAException.WRAPPED:
return translateWrappedException(ke);
default:
return translateGeneralException(ke);
}
@ -250,6 +253,18 @@ public class PersistenceExceptions
return e;
}
/*
* Translate the given wrapped exception. If contains an Exception, return
* the exception. If contains a Throwable, wrap the throwable and
* return it.
*/
private static Exception translateWrappedException(OpenJPAException ke) {
Throwable t = ke.getCause();
if (t instanceof Exception)
return (Exception)t;
return translateCause(ke);
}
/**
* Translate to a facade-level exception if the given exception
* a) has a cause i.e. one and only nested Throwable

View File

@ -23,7 +23,9 @@ import javax.persistence.ValidationMode;
import org.apache.openjpa.conf.OpenJPAConfiguration;
import org.apache.openjpa.lib.log.Log;
import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.lib.util.Localizer.Message;
import org.apache.openjpa.validation.ValidationException;
import org.apache.openjpa.validation.ValidationUnavailableException;
/**
@ -77,9 +79,11 @@ public class ValidationUtils {
} catch (ClassNotFoundException e) {
if (bValRequired) {
// fatal error - ValidationMode requires a validator
log.error(_loc.get("vlem-creation-error"), e);
// rethrow as a WrappedException
throw new ValidationException(
Message msg = _loc.get("vlem-creation-error");
log.error(msg, e);
// rethrow as a more descriptive/identifiable exception
throw new ValidationUnavailableException(
msg.getMessage(),
new RuntimeException(e), true);
} else {
// no optional validation provider, so just trace output
@ -105,9 +109,14 @@ public class ValidationUtils {
} catch (RuntimeException e) {
if (bValRequired) {
// fatal error - ValidationMode requires a validator
log.error(_loc.get("vlem-creation-error"), e);
// rethrow as a WrappedException
throw new ValidationException(e, true);
Message msg = _loc.get("vlem-creation-error");
log.error(msg, e);
// rethrow as a more descriptive/identifiable exception
throw new ValidationUnavailableException(
msg.getMessage(),
e, true);
} else {
// unexpected, but validation is optional,
// so just log it as a warning
@ -123,4 +132,21 @@ public class ValidationUtils {
}
return brc;
}
/**
* Determines whether an exception is a constraint violation exception via
* class name. Does not require JSR-303 API to be in classpath.
* @param e exception to check
* @return true of the exception is a constraint violation exception
*/
public static boolean isConstraintViolationException(Exception e) {
if (e == null)
return false;
if (e.getClass().getName().equals(
"javax.validation.ConstraintViolationException"))
return true;
return false;
}
}