Do not build exception instances in advance (#3983)
* Do not build exception instances in advance When no `cause` and no clean context of the exception thrown, the code place where an exception has been created is confusing. * Fix `SimpleMessageStore` to create an `out of capacity` exception in the `addMessagesToGroup()` exactly at the point where it is thrown * Fix `FunctionExpression` and `SupplierExpression` do not pre-create `readOnlyException`: it is unlikely these kind of expressions are going to be used in the SpEL `write` context, so we save some time and memory not creating extra object and the plain call `throw new` gives us a clean context what method call has ended up with such an exception * * Extract `outOfCapacityException` to the method in the `SimpleMessageStore` to avoid duplication. Even if we got in the end extra line in th stack trace, it is still clear from where it is thrown: ``` org.springframework.messaging.MessagingException: SimpleMessageStore was out of capacity (1) for group 'foo', try constructing it with a larger number. at org.springframework.integration.store.SimpleMessageStore.outOfCapacityException(SimpleMessageStore.java:324) at org.springframework.integration.store.SimpleMessageStore.addMessagesToGroup(SimpleMessageStore.java:302) at org.springframework.integration.store.AbstractMessageGroupStore.addMessageToGroup(AbstractMessageGroupStore.java:189) at org.springframework.integration.store.SimpleMessageStoreTests.shouldNotHoldMoreThanGroupCapacity(SimpleMessageStoreTests.java:128) ```
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2019 the original author or authors.
|
||||
* Copyright 2014-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -57,13 +57,9 @@ public class FunctionExpression<S> implements Expression {
|
||||
|
||||
private final EvaluationContext defaultContext = new StandardEvaluationContext();
|
||||
|
||||
private final EvaluationException readOnlyException;
|
||||
|
||||
public FunctionExpression(Function<S, ?> function) {
|
||||
Assert.notNull(function, "'function' must not be null.");
|
||||
this.function = function;
|
||||
this.readOnlyException = new EvaluationException(getExpressionString(),
|
||||
"FunctionExpression is a 'read only' Expression implementation");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -123,60 +119,65 @@ public class FunctionExpression<S> implements Expression {
|
||||
|
||||
@Override
|
||||
public Class<?> getValueType() throws EvaluationException {
|
||||
throw this.readOnlyException;
|
||||
throw readOnlyException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getValueType(@Nullable Object rootObject) throws EvaluationException {
|
||||
throw this.readOnlyException;
|
||||
throw readOnlyException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getValueType(EvaluationContext context) throws EvaluationException {
|
||||
throw this.readOnlyException;
|
||||
throw readOnlyException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getValueType(EvaluationContext context, @Nullable Object rootObject) throws EvaluationException {
|
||||
throw this.readOnlyException;
|
||||
throw readOnlyException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeDescriptor getValueTypeDescriptor() throws EvaluationException {
|
||||
throw this.readOnlyException;
|
||||
throw readOnlyException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeDescriptor getValueTypeDescriptor(@Nullable Object rootObject) throws EvaluationException {
|
||||
throw this.readOnlyException;
|
||||
throw readOnlyException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeDescriptor getValueTypeDescriptor(EvaluationContext context) throws EvaluationException {
|
||||
throw this.readOnlyException;
|
||||
throw readOnlyException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeDescriptor getValueTypeDescriptor(EvaluationContext context, @Nullable Object rootObject)
|
||||
throws EvaluationException {
|
||||
throw this.readOnlyException;
|
||||
throw readOnlyException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(EvaluationContext context, @Nullable Object value) throws EvaluationException {
|
||||
throw this.readOnlyException;
|
||||
throw readOnlyException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(@Nullable Object rootObject, @Nullable Object value) throws EvaluationException {
|
||||
throw this.readOnlyException;
|
||||
throw readOnlyException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(EvaluationContext context, @Nullable Object rootObject, @Nullable Object value)
|
||||
throws EvaluationException {
|
||||
|
||||
throw this.readOnlyException;
|
||||
throw readOnlyException();
|
||||
}
|
||||
|
||||
private EvaluationException readOnlyException() {
|
||||
return new EvaluationException(getExpressionString(),
|
||||
"FunctionExpression is a 'read only' Expression implementation");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2019 the original author or authors.
|
||||
* Copyright 2014-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -47,6 +47,7 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Artem Bilan
|
||||
* @author Gary Russell
|
||||
*
|
||||
* @since 5.0
|
||||
*/
|
||||
public class SupplierExpression<T> implements Expression {
|
||||
@@ -55,13 +56,9 @@ public class SupplierExpression<T> implements Expression {
|
||||
|
||||
private final EvaluationContext defaultContext = new StandardEvaluationContext();
|
||||
|
||||
private final EvaluationException readOnlyException;
|
||||
|
||||
public SupplierExpression(Supplier<T> supplier) {
|
||||
Assert.notNull(supplier, "'function' must not be null.");
|
||||
this.supplier = supplier;
|
||||
this.readOnlyException = new EvaluationException(getExpressionString(),
|
||||
"SupplierExpression is a 'read only' Expression implementation");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -108,58 +105,63 @@ public class SupplierExpression<T> implements Expression {
|
||||
|
||||
@Override
|
||||
public Class<?> getValueType() throws EvaluationException {
|
||||
throw this.readOnlyException;
|
||||
throw readOnlyException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getValueType(Object rootObject) throws EvaluationException {
|
||||
throw this.readOnlyException;
|
||||
throw readOnlyException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getValueType(EvaluationContext context) throws EvaluationException {
|
||||
throw this.readOnlyException;
|
||||
throw readOnlyException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getValueType(EvaluationContext context, Object rootObject) throws EvaluationException {
|
||||
throw this.readOnlyException;
|
||||
throw readOnlyException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeDescriptor getValueTypeDescriptor() throws EvaluationException {
|
||||
throw this.readOnlyException;
|
||||
throw readOnlyException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeDescriptor getValueTypeDescriptor(Object rootObject) throws EvaluationException {
|
||||
throw this.readOnlyException;
|
||||
throw readOnlyException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeDescriptor getValueTypeDescriptor(EvaluationContext context) throws EvaluationException {
|
||||
throw this.readOnlyException;
|
||||
throw readOnlyException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeDescriptor getValueTypeDescriptor(EvaluationContext context, Object rootObject)
|
||||
throws EvaluationException {
|
||||
throw this.readOnlyException;
|
||||
throw readOnlyException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(EvaluationContext context, Object value) throws EvaluationException {
|
||||
throw this.readOnlyException;
|
||||
throw readOnlyException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(Object rootObject, Object value) throws EvaluationException {
|
||||
throw this.readOnlyException;
|
||||
throw readOnlyException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(EvaluationContext context, Object rootObject, Object value) throws EvaluationException {
|
||||
throw this.readOnlyException;
|
||||
throw readOnlyException();
|
||||
}
|
||||
|
||||
private EvaluationException readOnlyException() {
|
||||
return new EvaluationException(getExpressionString(),
|
||||
"SupplierExpression is a 'read only' Expression implementation");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -127,6 +127,7 @@ public class SimpleMessageStore extends AbstractMessageGroupStore
|
||||
*/
|
||||
public SimpleMessageStore(int individualCapacity, int groupCapacity, long upperBoundTimeout,
|
||||
LockRegistry lockRegistry) {
|
||||
|
||||
super(false);
|
||||
Assert.notNull(lockRegistry, "The LockRegistry cannot be null");
|
||||
this.individualUpperBound = new UpperBound(individualCapacity);
|
||||
@@ -278,13 +279,9 @@ public class SimpleMessageStore extends AbstractMessageGroupStore
|
||||
try {
|
||||
UpperBound upperBound;
|
||||
MessageGroup group = this.groupIdToMessageGroup.get(groupId);
|
||||
MessagingException outOfCapacityException =
|
||||
new MessagingException(getClass().getSimpleName() +
|
||||
" was out of capacity (" + this.groupCapacity + ") for group '" + groupId +
|
||||
"', try constructing it with a larger capacity.");
|
||||
if (group == null) {
|
||||
if (this.groupCapacity > 0 && messages.length > this.groupCapacity) {
|
||||
throw outOfCapacityException;
|
||||
throw outOfCapacityException(groupId);
|
||||
}
|
||||
group = getMessageGroupFactory().create(groupId);
|
||||
this.groupIdToMessageGroup.put(groupId, group);
|
||||
@@ -302,7 +299,7 @@ public class SimpleMessageStore extends AbstractMessageGroupStore
|
||||
lock.unlock();
|
||||
if (!upperBound.tryAcquire(this.upperBoundTimeout)) {
|
||||
unlocked = true;
|
||||
throw outOfCapacityException;
|
||||
throw outOfCapacityException(groupId);
|
||||
}
|
||||
lock.lockInterruptibly();
|
||||
group.add(message);
|
||||
@@ -323,6 +320,12 @@ public class SimpleMessageStore extends AbstractMessageGroupStore
|
||||
}
|
||||
}
|
||||
|
||||
private MessagingException outOfCapacityException(Object groupId) {
|
||||
return new MessagingException(getClass().getSimpleName() +
|
||||
" was out of capacity (" + this.groupCapacity + ") for group '" + groupId +
|
||||
"', try constructing it with a larger number.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeMessageGroup(Object groupId) {
|
||||
Lock lock = this.lockRegistry.obtain(groupId);
|
||||
|
||||
Reference in New Issue
Block a user