PostFilter Support for Streams
Users can return a Stream from a @PostFilter-annotated method. Fixes: gh-3743
This commit is contained in:
parent
e1c7dd6480
commit
92e68a589a
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2016 the original author or authors.
|
* Copyright 2002-2018 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -20,6 +20,7 @@ import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.*;
|
||||||
|
|
||||||
import org.aopalliance.intercept.MethodInvocation;
|
import org.aopalliance.intercept.MethodInvocation;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
|
@ -86,8 +87,8 @@ public class DefaultMethodSecurityExpressionHandler extends
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filters the {@code filterTarget} object (which must be either a collection or an
|
* Filters the {@code filterTarget} object (which must be either a collection, array,
|
||||||
* array), by evaluating the supplied expression.
|
* or stream), by evaluating the supplied expression.
|
||||||
* <p>
|
* <p>
|
||||||
* If a {@code Collection} is used, the original instance will be modified to contain
|
* If a {@code Collection} is used, the original instance will be modified to contain
|
||||||
* the elements for which the permission expression evaluates to {@code true}. For an
|
* the elements for which the permission expression evaluates to {@code true}. For an
|
||||||
|
@ -172,8 +173,27 @@ public class DefaultMethodSecurityExpressionHandler extends
|
||||||
return filtered;
|
return filtered;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (filterTarget instanceof Stream) {
|
||||||
|
final Stream<?> original = (Stream<?>) filterTarget;
|
||||||
|
if (debug) {
|
||||||
|
logger.debug("Filtering stream with " + original.count() + " elements");
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<?> filtered = original.filter(filterObject -> {
|
||||||
|
rootObject.setFilterObject(filterObject);
|
||||||
|
return ExpressionUtils.evaluateAsBoolean(filterExpression, ctx);
|
||||||
|
})
|
||||||
|
.onClose(original::close);
|
||||||
|
|
||||||
|
if (debug) {
|
||||||
|
logger.debug("Retaining elements: " + filtered.collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return filtered;
|
||||||
|
}
|
||||||
|
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Filter target must be a collection or array type, but was "
|
"Filter target must be a collection, array, or stream type, but was "
|
||||||
+ filterTarget);
|
+ filterTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2016 the original author or authors.
|
* Copyright 2002-2018 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -19,6 +19,7 @@ import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
import org.aopalliance.intercept.MethodInvocation;
|
import org.aopalliance.intercept.MethodInvocation;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
@ -30,6 +31,9 @@ import org.springframework.security.authentication.AuthenticationTrustResolver;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.*;
|
||||||
|
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
public class DefaultMethodSecurityExpressionHandlerTests {
|
public class DefaultMethodSecurityExpressionHandlerTests {
|
||||||
private DefaultMethodSecurityExpressionHandler handler;
|
private DefaultMethodSecurityExpressionHandler handler;
|
||||||
|
@ -68,4 +72,22 @@ public class DefaultMethodSecurityExpressionHandlerTests {
|
||||||
|
|
||||||
verify(trustResolver).isAnonymous(authentication);
|
verify(trustResolver).isAnonymous(authentication);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void testFilteringStream() {
|
||||||
|
final Stream<String> stream = Stream.of("1", "2", "3");
|
||||||
|
|
||||||
|
Expression expression = handler.getExpressionParser().parseExpression("filterObject ne '2'");
|
||||||
|
|
||||||
|
EvaluationContext context = handler.createEvaluationContext(authentication,
|
||||||
|
methodInvocation);
|
||||||
|
|
||||||
|
Object filtered = handler.filter(stream, expression, context);
|
||||||
|
|
||||||
|
Assert.assertTrue("response was wrong type", Stream.class.isAssignableFrom(filtered.getClass()));
|
||||||
|
List<String> list = ((Stream<String>) filtered).collect(Collectors.toList());
|
||||||
|
Assert.assertEquals(2, list.size());
|
||||||
|
Assert.assertFalse("contains filtered element", list.contains("2"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue