Skip to content

Commit c15f23b

Browse files
committed
Reliably expose nested cause exception message for PersistenceException
Issue: SPR-16559 (cherry picked from commit eb9c43d)
1 parent 0962c66 commit c15f23b

File tree

3 files changed

+51
-18
lines changed

3 files changed

+51
-18
lines changed

spring-core/src/test/java/org/springframework/core/NestedExceptionTests.java

+15-15
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -44,28 +44,28 @@ public void nestedRuntimeExceptionWithNoRootCause() {
4444
nex.printStackTrace(pw);
4545
pw.flush();
4646
String stackTrace = new String(baos.toByteArray());
47-
assertFalse(stackTrace.indexOf(mesg) == -1);
47+
assertTrue(stackTrace.contains(mesg));
4848
}
4949

5050
@Test
5151
public void nestedRuntimeExceptionWithRootCause() {
5252
String myMessage = "mesg for this exception";
53-
String rootCauseMesg = "this is the obscure message of the root cause";
54-
Exception rootCause = new Exception(rootCauseMesg);
53+
String rootCauseMsg = "this is the obscure message of the root cause";
54+
Exception rootCause = new Exception(rootCauseMsg);
5555
// Making a class abstract doesn't _really_ prevent instantiation :-)
5656
NestedRuntimeException nex = new NestedRuntimeException(myMessage, rootCause) {};
5757
assertEquals(nex.getCause(), rootCause);
58-
assertTrue(nex.getMessage().indexOf(myMessage) != -1);
59-
assertTrue(nex.getMessage().indexOf(rootCauseMesg) != -1);
58+
assertTrue(nex.getMessage().contains(myMessage));
59+
assertTrue(nex.getMessage().endsWith(rootCauseMsg));
6060

6161
// check PrintStackTrace
6262
ByteArrayOutputStream baos = new ByteArrayOutputStream();
6363
PrintWriter pw = new PrintWriter(baos);
6464
nex.printStackTrace(pw);
6565
pw.flush();
6666
String stackTrace = new String(baos.toByteArray());
67-
assertFalse(stackTrace.indexOf(rootCause.getClass().getName()) == -1);
68-
assertFalse(stackTrace.indexOf(rootCauseMesg) == -1);
67+
assertTrue(stackTrace.contains(rootCause.getClass().getName()));
68+
assertTrue(stackTrace.contains(rootCauseMsg));
6969
}
7070

7171
@Test
@@ -82,28 +82,28 @@ public void nestedCheckedExceptionWithNoRootCause() {
8282
nex.printStackTrace(pw);
8383
pw.flush();
8484
String stackTrace = new String(baos.toByteArray());
85-
assertFalse(stackTrace.indexOf(mesg) == -1);
85+
assertTrue(stackTrace.contains(mesg));
8686
}
8787

8888
@Test
8989
public void nestedCheckedExceptionWithRootCause() {
9090
String myMessage = "mesg for this exception";
91-
String rootCauseMesg = "this is the obscure message of the root cause";
92-
Exception rootCause = new Exception(rootCauseMesg);
91+
String rootCauseMsg = "this is the obscure message of the root cause";
92+
Exception rootCause = new Exception(rootCauseMsg);
9393
// Making a class abstract doesn't _really_ prevent instantiation :-)
9494
NestedCheckedException nex = new NestedCheckedException(myMessage, rootCause) {};
9595
assertEquals(nex.getCause(), rootCause);
96-
assertTrue(nex.getMessage().indexOf(myMessage) != -1);
97-
assertTrue(nex.getMessage().indexOf(rootCauseMesg) != -1);
96+
assertTrue(nex.getMessage().contains(myMessage));
97+
assertTrue(nex.getMessage().endsWith(rootCauseMsg));
9898

9999
// check PrintStackTrace
100100
ByteArrayOutputStream baos = new ByteArrayOutputStream();
101101
PrintWriter pw = new PrintWriter(baos);
102102
nex.printStackTrace(pw);
103103
pw.flush();
104104
String stackTrace = new String(baos.toByteArray());
105-
assertFalse(stackTrace.indexOf(rootCause.getClass().getName()) == -1);
106-
assertFalse(stackTrace.indexOf(rootCauseMesg) == -1);
105+
assertTrue(stackTrace.contains(rootCause.getClass().getName()));
106+
assertTrue(stackTrace.contains(rootCauseMsg));
107107
}
108108

109109
}

spring-orm-hibernate5/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBuilder.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -427,8 +427,13 @@ private SessionFactory getSessionFactory() {
427427
throw new IllegalStateException("Interrupted during initialization of Hibernate SessionFactory", ex);
428428
}
429429
catch (ExecutionException ex) {
430+
Throwable cause = ex.getCause();
431+
if (cause instanceof HibernateException) {
432+
// Rethrow a provider configuration exception (possibly with a nested cause) directly
433+
throw (HibernateException) cause;
434+
}
430435
throw new IllegalStateException("Failed to asynchronously initialize Hibernate SessionFactory: " +
431-
ex.getMessage(), ex.getCause());
436+
ex.getMessage(), cause);
432437
}
433438
}
434439
}

spring-orm/src/main/java/org/springframework/orm/jpa/AbstractEntityManagerFactoryBean.java

+30-2
Original file line numberDiff line numberDiff line change
@@ -379,15 +379,37 @@ public EntityManagerFactory call() {
379379
}
380380

381381
private EntityManagerFactory buildNativeEntityManagerFactory() {
382-
EntityManagerFactory emf = createNativeEntityManagerFactory();
382+
EntityManagerFactory emf;
383+
try {
384+
emf = createNativeEntityManagerFactory();
385+
}
386+
catch (PersistenceException ex) {
387+
if (ex.getClass() == PersistenceException.class) {
388+
// Plain PersistenceException wrapper for underlying exception?
389+
// Make sure the nested exception message is properly exposed,
390+
// along the lines of Spring's NestedRuntimeException.getMessage()
391+
Throwable cause = ex.getCause();
392+
if (cause != null) {
393+
String message = ex.getMessage();
394+
String causeString = cause.toString();
395+
if (!message.endsWith(causeString)) {
396+
throw new PersistenceException(message + "; nested exception is " + causeString, cause);
397+
}
398+
}
399+
}
400+
throw ex;
401+
}
402+
383403
if (emf == null) {
384404
throw new IllegalStateException(
385405
"JPA PersistenceProvider returned null EntityManagerFactory - check your JPA provider setup!");
386406
}
407+
387408
JpaVendorAdapter jpaVendorAdapter = getJpaVendorAdapter();
388409
if (jpaVendorAdapter != null) {
389410
jpaVendorAdapter.postProcessEntityManagerFactory(emf);
390411
}
412+
391413
if (logger.isInfoEnabled()) {
392414
logger.info("Initialized JPA EntityManagerFactory for persistence unit '" + getPersistenceUnitName() + "'");
393415
}
@@ -414,6 +436,7 @@ else if (emf != null) {
414436
ifcs.add(EntityManagerFactory.class);
415437
}
416438
ifcs.add(EntityManagerFactoryInfo.class);
439+
417440
try {
418441
return (EntityManagerFactory) Proxy.newProxyInstance(this.beanClassLoader,
419442
ClassUtils.toClassArray(ifcs), new ManagedEntityManagerFactoryInvocationHandler(this));
@@ -517,8 +540,13 @@ public EntityManagerFactory getNativeEntityManagerFactory() {
517540
throw new IllegalStateException("Interrupted during initialization of native EntityManagerFactory", ex);
518541
}
519542
catch (ExecutionException ex) {
543+
Throwable cause = ex.getCause();
544+
if (cause instanceof PersistenceException) {
545+
// Rethrow a provider configuration exception (possibly with a nested cause) directly
546+
throw (PersistenceException) cause;
547+
}
520548
throw new IllegalStateException("Failed to asynchronously initialize native EntityManagerFactory: " +
521-
ex.getMessage(), ex.getCause());
549+
ex.getMessage(), cause);
522550
}
523551
}
524552
}

0 commit comments

Comments
 (0)