Skip to content

Commit 80f8d61

Browse files
committed
Only log the exception if is it resolved
This commit improves AbstractEndpointExceptionResolver to only invoke the logException method for an exception that has been resolved. To help with chaining them, a CompositeEndpointExceptionResolver has been introduced. If no resolvers were able to resolve the exception, the last instance will then log the exception. Closes gh-736
1 parent d3454c5 commit 80f8d61

File tree

3 files changed

+144
-3
lines changed

3 files changed

+144
-3
lines changed

spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/AbstractEndpointExceptionResolver.java

+5-3
Original file line numberDiff line numberDiff line change
@@ -100,12 +100,14 @@ public final boolean resolveException(MessageContext messageContext, Object endp
100100
if (this.mappedEndpoints != null && !this.mappedEndpoints.contains(mappedEndpoint)) {
101101
return false;
102102
}
103-
// Log exception, both at debug log level and at warn level, if desired.
104103
if (this.logger.isDebugEnabled()) {
105104
this.logger.debug("Resolving exception from endpoint [" + endpoint + "]: " + ex);
106105
}
107-
logException(ex, messageContext);
108-
return resolveExceptionInternal(messageContext, endpoint, ex);
106+
boolean resolved = resolveExceptionInternal(messageContext, endpoint, ex);
107+
if (resolved) {
108+
logException(ex, messageContext);
109+
}
110+
return resolved;
109111
}
110112

111113
/**
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright 2005-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.ws.server.endpoint;
18+
19+
import org.springframework.ws.context.MessageContext;
20+
import org.springframework.ws.server.EndpointExceptionResolver;
21+
22+
/**
23+
* A composite of {@linkplain AbstractEndpointExceptionResolver endpoint exception
24+
* resolvers}.
25+
*
26+
* @author Stephane Nicoll
27+
* @since 4.1.0
28+
*/
29+
public class CompositeEndpointExceptionResolver implements EndpointExceptionResolver {
30+
31+
private final Iterable<AbstractEndpointExceptionResolver> resolvers;
32+
33+
public CompositeEndpointExceptionResolver(Iterable<AbstractEndpointExceptionResolver> resolvers) {
34+
this.resolvers = resolvers;
35+
}
36+
37+
@Override
38+
public final boolean resolveException(MessageContext messageContext, Object endpoint, Exception ex) {
39+
AbstractEndpointExceptionResolver currentResolver = null;
40+
for (AbstractEndpointExceptionResolver resolver : this.resolvers) {
41+
currentResolver = resolver;
42+
if (currentResolver.resolveException(messageContext, endpoint, ex)) {
43+
return true;
44+
}
45+
}
46+
if (currentResolver != null) {
47+
currentResolver.logException(ex, messageContext);
48+
}
49+
return false;
50+
}
51+
52+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Copyright 2005-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.ws.server.endpoint;
18+
19+
import java.util.List;
20+
21+
import org.junit.jupiter.api.Test;
22+
23+
import org.springframework.ws.context.MessageContext;
24+
25+
import static org.assertj.core.api.Assertions.assertThat;
26+
27+
/**
28+
* Tests for {@link CompositeEndpointExceptionResolver}.
29+
*
30+
* @author Stephane Nicoll
31+
*/
32+
class CompositeEndpointExceptionResolverTest {
33+
34+
@Test
35+
void logExceptionIsInvokedOnlyOnResolvedInstance() {
36+
TestExceptionResolver first = new TestExceptionResolver(false);
37+
TestExceptionResolver second = new TestExceptionResolver(true);
38+
TestExceptionResolver third = new TestExceptionResolver(false);
39+
CompositeEndpointExceptionResolver resolver = new CompositeEndpointExceptionResolver(
40+
List.of(first, second, third));
41+
boolean resolved = resolver.resolveException(null, null, new RuntimeException("test"));
42+
assertThat(resolved).isTrue();
43+
assertThat(first.logException).isFalse();
44+
assertThat(second.logException).isTrue();
45+
assertThat(third.logException).isFalse();
46+
}
47+
48+
@Test
49+
void logExceptionIsInvokedOnLastResolvedInstanceIfNecessary() {
50+
TestExceptionResolver first = new TestExceptionResolver(false);
51+
TestExceptionResolver second = new TestExceptionResolver(false);
52+
TestExceptionResolver third = new TestExceptionResolver(false);
53+
CompositeEndpointExceptionResolver resolver = new CompositeEndpointExceptionResolver(
54+
List.of(first, second, third));
55+
boolean resolved = resolver.resolveException(null, null, new RuntimeException("test"));
56+
assertThat(resolved).isFalse();
57+
assertThat(first.logException).isFalse();
58+
assertThat(second.logException).isFalse();
59+
assertThat(third.logException).isTrue();
60+
}
61+
62+
public static class TestExceptionResolver extends AbstractEndpointExceptionResolver {
63+
64+
private final boolean resolve;
65+
66+
private boolean logException;
67+
68+
public TestExceptionResolver(boolean resolve) {
69+
this.resolve = resolve;
70+
}
71+
72+
@Override
73+
protected boolean resolveExceptionInternal(MessageContext messageContext, Object endpoint, Exception ex) {
74+
return this.resolve;
75+
}
76+
77+
@Override
78+
protected void logException(Exception ex, MessageContext messageContext) {
79+
if (this.logException) {
80+
throw new IllegalStateException("Log exception already called");
81+
}
82+
this.logException = true;
83+
}
84+
85+
}
86+
87+
}

0 commit comments

Comments
 (0)