Skip to content

Commit 5d2fd75

Browse files
committed
Introduce Servlet.fn
This commit introduces Servlet.fn, a servlet-based version of WebFlux.fn, i.e. HandlerFunctions and RouterFunctions. This commit contains the web framework only, further commits provide tests and DispatcherServlet integration. See spring-projectsgh-21490
1 parent 7d498ba commit 5d2fd75

20 files changed

+6153
-0
lines changed

spring-webmvc/src/main/java/org/springframework/web/servlet/function/DefaultEntityResponseBuilder.java

Lines changed: 469 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
/*
2+
* Copyright 2002-2019 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+
* http://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.web.servlet.function;
18+
19+
import java.util.Arrays;
20+
import java.util.Collection;
21+
import java.util.Collections;
22+
import java.util.LinkedHashMap;
23+
import java.util.Map;
24+
import java.util.function.Consumer;
25+
import javax.servlet.http.Cookie;
26+
import javax.servlet.http.HttpServletRequest;
27+
import javax.servlet.http.HttpServletResponse;
28+
29+
import org.springframework.core.Conventions;
30+
import org.springframework.http.HttpHeaders;
31+
import org.springframework.http.HttpStatus;
32+
import org.springframework.lang.Nullable;
33+
import org.springframework.util.Assert;
34+
import org.springframework.util.LinkedMultiValueMap;
35+
import org.springframework.util.MultiValueMap;
36+
import org.springframework.web.servlet.ModelAndView;
37+
38+
/**
39+
* Default {@link RenderingResponse.Builder} implementation.
40+
*
41+
* @author Arjen Poutsma
42+
* @since 5.1
43+
*/
44+
final class DefaultRenderingResponseBuilder implements RenderingResponse.Builder {
45+
46+
private final String name;
47+
48+
private int status = HttpStatus.OK.value();
49+
50+
private final HttpHeaders headers = new HttpHeaders();
51+
52+
private final MultiValueMap<String, Cookie> cookies = new LinkedMultiValueMap<>();
53+
54+
private final Map<String, Object> model = new LinkedHashMap<>();
55+
56+
57+
public DefaultRenderingResponseBuilder(RenderingResponse other) {
58+
Assert.notNull(other, "RenderingResponse must not be null");
59+
this.name = other.name();
60+
this.status = (other instanceof DefaultRenderingResponse ?
61+
((DefaultRenderingResponse) other).statusCode : other.statusCode().value());
62+
this.headers.putAll(other.headers());
63+
this.model.putAll(other.model());
64+
}
65+
66+
public DefaultRenderingResponseBuilder(String name) {
67+
Assert.notNull(name, "Name must not be null");
68+
this.name = name;
69+
}
70+
71+
72+
@Override
73+
public RenderingResponse.Builder status(HttpStatus status) {
74+
Assert.notNull(status, "HttpStatus must not be null");
75+
this.status = status.value();
76+
return this;
77+
}
78+
79+
@Override
80+
public RenderingResponse.Builder status(int status) {
81+
this.status = status;
82+
return this;
83+
}
84+
85+
@Override
86+
public RenderingResponse.Builder cookie(Cookie cookie) {
87+
Assert.notNull(cookie, "Cookie must not be null");
88+
this.cookies.add(cookie.getName(), cookie);
89+
return this;
90+
}
91+
92+
@Override
93+
public RenderingResponse.Builder cookies(Consumer<MultiValueMap<String, Cookie>> cookiesConsumer) {
94+
cookiesConsumer.accept(this.cookies);
95+
return this;
96+
}
97+
98+
@Override
99+
public RenderingResponse.Builder modelAttribute(Object attribute) {
100+
Assert.notNull(attribute, "Attribute must not be null");
101+
if (attribute instanceof Collection && ((Collection<?>) attribute).isEmpty()) {
102+
return this;
103+
}
104+
return modelAttribute(Conventions.getVariableName(attribute), attribute);
105+
}
106+
107+
@Override
108+
public RenderingResponse.Builder modelAttribute(String name, @Nullable Object value) {
109+
Assert.notNull(name, "Name must not be null");
110+
this.model.put(name, value);
111+
return this;
112+
}
113+
114+
@Override
115+
public RenderingResponse.Builder modelAttributes(Object... attributes) {
116+
modelAttributes(Arrays.asList(attributes));
117+
return this;
118+
}
119+
120+
@Override
121+
public RenderingResponse.Builder modelAttributes(Collection<?> attributes) {
122+
attributes.forEach(this::modelAttribute);
123+
return this;
124+
}
125+
126+
@Override
127+
public RenderingResponse.Builder modelAttributes(Map<String, ?> attributes) {
128+
this.model.putAll(attributes);
129+
return this;
130+
}
131+
132+
@Override
133+
public RenderingResponse.Builder header(String headerName, String... headerValues) {
134+
for (String headerValue : headerValues) {
135+
this.headers.add(headerName, headerValue);
136+
}
137+
return this;
138+
}
139+
140+
@Override
141+
public RenderingResponse.Builder headers(HttpHeaders headers) {
142+
this.headers.putAll(headers);
143+
return this;
144+
}
145+
146+
@Override
147+
public RenderingResponse build() {
148+
return new DefaultRenderingResponse(this.status, this.headers, this.cookies, this.name, this.model);
149+
}
150+
151+
152+
private static final class DefaultRenderingResponse extends DefaultServerResponseBuilder.AbstractServerResponse
153+
implements RenderingResponse {
154+
155+
private final String name;
156+
157+
private final Map<String, Object> model;
158+
159+
public DefaultRenderingResponse(int statusCode, HttpHeaders headers,
160+
MultiValueMap<String, Cookie> cookies, String name, Map<String, Object> model) {
161+
162+
super(statusCode, headers, cookies);
163+
this.name = name;
164+
this.model = Collections.unmodifiableMap(new LinkedHashMap<>(model));
165+
}
166+
167+
@Override
168+
public String name() {
169+
return this.name;
170+
}
171+
172+
@Override
173+
public Map<String, Object> model() {
174+
return this.model;
175+
}
176+
177+
@Override
178+
protected ModelAndView writeToInternal(HttpServletRequest request,
179+
HttpServletResponse response, Context context) {
180+
181+
HttpStatus status = HttpStatus.resolve(this.statusCode);
182+
ModelAndView mav;
183+
if (status != null) {
184+
mav = new ModelAndView(this.name, status);
185+
}
186+
else {
187+
mav = new ModelAndView(this.name);
188+
}
189+
mav.addAllObjects(this.model);
190+
return mav;
191+
}
192+
193+
}
194+
195+
}

0 commit comments

Comments
 (0)