Skip to content

Commit abfbe20

Browse files
committed
WIP
1 parent 57ac32b commit abfbe20

File tree

8 files changed

+420
-0
lines changed

8 files changed

+420
-0
lines changed

spring-webflux/src/main/java/org/springframework/web/reactive/function/server/ChangePathPatternParserVisitor.java

+5
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.web.reactive.function.server;
1818

19+
import java.util.Map;
1920
import java.util.function.Function;
2021

2122
import reactor.core.publisher.Mono;
@@ -60,6 +61,10 @@ public void route(RequestPredicate predicate, HandlerFunction<?> handlerFunction
6061
public void resources(Function<ServerRequest, Mono<Resource>> lookupFunction) {
6162
}
6263

64+
@Override
65+
public void attributes(Map<String, Object> attributes) {
66+
}
67+
6368
@Override
6469
public void unknown(RouterFunction<?> routerFunction) {
6570
}

spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RouterFunction.java

+41
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,14 @@
1616

1717
package org.springframework.web.reactive.function.server;
1818

19+
import java.util.LinkedHashMap;
20+
import java.util.Map;
21+
import java.util.function.Consumer;
22+
1923
import reactor.core.publisher.Mono;
2024

25+
import org.springframework.util.Assert;
26+
2127
/**
2228
* Represents a function that routes to a {@linkplain HandlerFunction handler function}.
2329
*
@@ -115,4 +121,39 @@ default void accept(RouterFunctions.Visitor visitor) {
115121
visitor.unknown(this);
116122
}
117123

124+
/**
125+
* Return a new routing function with the given attribute.
126+
* @param name the attribute name
127+
* @param value the attribute value
128+
* @return a function that has the specified attributes
129+
* @since 5.3
130+
*/
131+
default RouterFunction<T> withAttribute(String name, Object value) {
132+
Assert.hasLength(name, "Name must not be empty");
133+
Assert.notNull(value, "Value must not be null");
134+
135+
Map<String, Object> attributes = new LinkedHashMap<>();
136+
attributes.put(name, value);
137+
return new RouterFunctions.AttributesRouterFunction<>(this, attributes);
138+
}
139+
140+
/**
141+
* Return a new routing function with attributes manipulated with the given consumer.
142+
* <p>The map provided to the consumer is "live", so that the consumer can be used
143+
* to {@linkplain Map#put(Object, Object) overwrite} existing attributes,
144+
* {@linkplain Map#remove(Object) remove} attributes, or use any of the other
145+
* {@link Map} methods.
146+
* @param attributesConsumer a function that consumes the attributes map
147+
* @return this builder
148+
* @since 5.3
149+
*/
150+
default RouterFunction<T> withAttributes(Consumer<Map<String, Object>> attributesConsumer) {
151+
Assert.notNull(attributesConsumer, "AttributesConsumer must not be null");
152+
153+
Map<String, Object> attributes = new LinkedHashMap<>();
154+
attributesConsumer.accept(attributes);
155+
return new RouterFunctions.AttributesRouterFunction<>(this, attributes);
156+
}
157+
158+
118159
}

spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RouterFunctionBuilder.java

+30
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import java.util.ArrayList;
2020
import java.util.List;
21+
import java.util.Map;
2122
import java.util.function.BiFunction;
2223
import java.util.function.Consumer;
2324
import java.util.function.Function;
@@ -330,6 +331,35 @@ public <T extends Throwable> RouterFunctions.Builder onError(Class<T> exceptionT
330331
return this;
331332
}
332333

334+
@Override
335+
public RouterFunctions.Builder withAttribute(String name, Object value) {
336+
Assert.hasLength(name, "Name must not be empty");
337+
Assert.notNull(value, "Value must not be null");
338+
339+
if (this.routerFunctions.isEmpty()) {
340+
throw new IllegalStateException("attributes can only be called after any other method (GET, path, etc.)");
341+
}
342+
int lastIdx = this.routerFunctions.size() - 1;
343+
RouterFunction<ServerResponse> attributed = this.routerFunctions.get(lastIdx)
344+
.withAttribute(name, value);
345+
this.routerFunctions.set(lastIdx, attributed);
346+
return this;
347+
}
348+
349+
@Override
350+
public RouterFunctions.Builder withAttributes(Consumer<Map<String, Object>> attributesConsumer) {
351+
Assert.notNull(attributesConsumer, "AttributesConsumer must not be null");
352+
353+
if (this.routerFunctions.isEmpty()) {
354+
throw new IllegalStateException("attributes can only be called after any other method (GET, path, etc.)");
355+
}
356+
int lastIdx = this.routerFunctions.size() - 1;
357+
RouterFunction<ServerResponse> attributed = this.routerFunctions.get(lastIdx)
358+
.withAttributes(attributesConsumer);
359+
this.routerFunctions.set(lastIdx, attributed);
360+
return this;
361+
}
362+
333363
@Override
334364
public RouterFunction<ServerResponse> build() {
335365
if (this.routerFunctions.isEmpty()) {

spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RouterFunctions.java

+83
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package org.springframework.web.reactive.function.server;
1818

19+
import java.util.Collections;
20+
import java.util.LinkedHashMap;
1921
import java.util.List;
2022
import java.util.Map;
2123
import java.util.function.BiFunction;
@@ -858,6 +860,27 @@ Builder onError(Predicate<? super Throwable> predicate,
858860
<T extends Throwable> Builder onError(Class<T> exceptionType,
859861
BiFunction<? super T, ServerRequest, Mono<ServerResponse>> responseProvider);
860862

863+
/**
864+
* Add an attribute with the given name and value to the last route built with this builder.
865+
* @param name the attribute name
866+
* @param value the attribute value
867+
* @return this builder
868+
* @since 5.3
869+
*/
870+
Builder withAttribute(String name, Object value);
871+
872+
/**
873+
* Manipulate the attributes of the last route built with the given consumer.
874+
* <p>The map provided to the consumer is "live", so that the consumer can be used
875+
* to {@linkplain Map#put(Object, Object) overwrite} existing attributes,
876+
* {@linkplain Map#remove(Object) remove} attributes, or use any of the other
877+
* {@link Map} methods.
878+
* @param attributesConsumer a function that consumes the attributes map
879+
* @return this builder
880+
* @since 5.3
881+
*/
882+
Builder withAttributes(Consumer<Map<String, Object>> attributesConsumer);
883+
861884
/**
862885
* Builds the {@code RouterFunction}. All created routes are
863886
* {@linkplain RouterFunction#and(RouterFunction) composed} with one another, and filters
@@ -902,6 +925,14 @@ public interface Visitor {
902925
*/
903926
void resources(Function<ServerRequest, Mono<Resource>> lookupFunction);
904927

928+
/**
929+
* Receive notification of a router function with attributes. The
930+
* given attributes apply to the router notification that follows this one.
931+
* @param attributes the attributes that apply to the following router
932+
* @since 5.3
933+
*/
934+
void attributes(Map<String, Object> attributes);
935+
905936
/**
906937
* Receive notification of an unknown router function. This method is called for router
907938
* functions that were not created via the various {@link RouterFunctions} methods.
@@ -1126,6 +1157,58 @@ public void accept(Visitor visitor) {
11261157
}
11271158

11281159

1160+
static final class AttributesRouterFunction<T extends ServerResponse> extends AbstractRouterFunction<T> {
1161+
1162+
private final RouterFunction<T> delegate;
1163+
1164+
private final Map<String,Object> attributes;
1165+
1166+
public AttributesRouterFunction(RouterFunction<T> delegate, Map<String, Object> attributes) {
1167+
this.delegate = delegate;
1168+
this.attributes = initAttributes(attributes);
1169+
}
1170+
1171+
private static Map<String, Object> initAttributes(Map<String, Object> attributes) {
1172+
if (attributes.isEmpty()) {
1173+
return Collections.emptyMap();
1174+
}
1175+
else {
1176+
return Collections.unmodifiableMap(new LinkedHashMap<>(attributes));
1177+
}
1178+
}
1179+
1180+
@Override
1181+
public Mono<HandlerFunction<T>> route(ServerRequest request) {
1182+
return this.delegate.route(request);
1183+
}
1184+
1185+
@Override
1186+
public void accept(Visitor visitor) {
1187+
visitor.attributes(this.attributes);
1188+
this.delegate.accept(visitor);
1189+
}
1190+
1191+
@Override
1192+
public RouterFunction<T> withAttribute(String name, Object value) {
1193+
Assert.hasLength(name, "Name must not be empty");
1194+
Assert.notNull(value, "Value must not be null");
1195+
1196+
Map<String, Object> attributes = new LinkedHashMap<>(this.attributes);
1197+
attributes.put(name, value);
1198+
return new AttributesRouterFunction<>(this.delegate, attributes);
1199+
}
1200+
1201+
@Override
1202+
public RouterFunction<T> withAttributes(Consumer<Map<String, Object>> attributesConsumer) {
1203+
Assert.notNull(attributesConsumer, "AttributesConsumer must not be null");
1204+
1205+
Map<String, Object> attributes = new LinkedHashMap<>(this.attributes);
1206+
attributesConsumer.accept(attributes);
1207+
return new AttributesRouterFunction<>(this.delegate, attributes);
1208+
}
1209+
}
1210+
1211+
11291212
private static class HandlerStrategiesResponseContext implements ServerResponse.Context {
11301213

11311214
private final HandlerStrategies strategies;

spring-webflux/src/main/java/org/springframework/web/reactive/function/server/ToStringVisitor.java

+5
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.web.reactive.function.server;
1818

19+
import java.util.Map;
1920
import java.util.Set;
2021
import java.util.function.Function;
2122

@@ -69,6 +70,10 @@ public void resources(Function<ServerRequest, Mono<Resource>> lookupFunction) {
6970
this.builder.append(lookupFunction).append('\n');
7071
}
7172

73+
@Override
74+
public void attributes(Map<String, Object> attributes) {
75+
}
76+
7277
@Override
7378
public void unknown(RouterFunction<?> routerFunction) {
7479
indent();

0 commit comments

Comments
 (0)