• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

aspectran / aspectran / #4057

11 Feb 2025 06:00AM CUT coverage: 35.269% (+1.9%) from 33.377%
#4057

push

github

topframe
Update

13 of 42 new or added lines in 7 files covered. (30.95%)

4 existing lines in 3 files now uncovered.

14247 of 40395 relevant lines covered (35.27%)

0.35 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/web/src/main/java/com/aspectran/web/activity/response/AbstractRestResponse.java
1
/*
2
 * Copyright (c) 2008-2025 The Aspectran Project
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
package com.aspectran.web.activity.response;
17

18
import com.aspectran.core.activity.Activity;
19
import com.aspectran.utils.Assert;
20
import com.aspectran.utils.FilenameUtils;
21
import com.aspectran.utils.LinkedCaseInsensitiveMultiValueMap;
22
import com.aspectran.utils.MultiValueMap;
23
import com.aspectran.utils.StringUtils;
24
import com.aspectran.utils.StringifyContext;
25
import com.aspectran.utils.annotation.jsr305.NonNull;
26
import com.aspectran.utils.annotation.jsr305.Nullable;
27
import com.aspectran.web.activity.request.RequestHeaderParser;
28
import com.aspectran.web.support.http.HttpHeaders;
29
import com.aspectran.web.support.http.HttpMediaTypeNotAcceptableException;
30
import com.aspectran.web.support.http.HttpStatus;
31
import com.aspectran.web.support.http.MediaType;
32

33
import java.nio.charset.Charset;
34
import java.util.List;
35
import java.util.Locale;
36

37
/**
38
 * Abstract class shared by RestResponse.
39
 *
40
 * <p>Created: 2019-06-16</p>
41
 */
42
public abstract class AbstractRestResponse implements RestResponse {
43

44
    private String name;
45

46
    private Object data;
47

48
    private StringifyContext stringifyContext;
49

50
    private boolean favorPathExtension = true;
×
51

52
    private boolean ignoreUnknownPathExtensions = true;
×
53

54
    private boolean ignoreAcceptHeader = false;
×
55

56
    private MediaType defaultContentType;
57

58
    private int status;
59

60
    private MultiValueMap<String, String> headers;
61

62
    public AbstractRestResponse() {
×
63
    }
×
64

65
    public AbstractRestResponse(Object data) {
66
        this(null, data);
×
67
    }
×
68

69
    public AbstractRestResponse(String name, Object data) {
×
70
        setData(name, data);
×
71
    }
×
72

73
    @Override
74
    public String getName() {
75
        return name;
×
76
    }
77

78
    @Override
79
    public Object getData() {
80
        return data;
×
81
    }
82

83
    @Override
84
    public boolean hasData() {
85
        return (data != null);
×
86
    }
87

88
    @Override
89
    public RestResponse setData(Object data) {
90
        return setData(null, data);
×
91
    }
92

93
    @Override
94
    public RestResponse setData(String name, Object data) {
95
        if (name != null) {
×
96
            name = name.trim();
×
97
            if (name.isEmpty()) {
×
98
                name = null;
×
99
            }
100
        }
101
        this.name = name;
×
102
        this.data = data;
×
103
        return this;
×
104
    }
105

106
    @Override
107
    @Nullable
108
    public StringifyContext getStringifyContext() {
109
        return stringifyContext;
×
110
    }
111

112
    @Override
113
    @NonNull
114
    public StringifyContext touchStringifyContext() {
115
        if (stringifyContext == null) {
×
116
            stringifyContext = new StringifyContext();
×
117
        }
118
        return stringifyContext;
×
119
    }
120

121
    @Override
122
    public void setStringifyContext(StringifyContext stringifyContext) {
123
        this.stringifyContext = stringifyContext;
×
124
    }
×
125

126
    @Override
127
    public RestResponse stringifyContext(StringifyContext stringifyContext) {
128
        setStringifyContext(stringifyContext);
×
129
        return this;
×
130
    }
131

132
    @Override
133
    public RestResponse prettyPrint(boolean prettyPrint) {
NEW
134
        touchStringifyContext().setPrettyPrint(prettyPrint);
×
NEW
135
        return this;
×
136
    }
137

138
    @Override
139
    public RestResponse nullWritable(boolean nullWritable) {
140
        touchStringifyContext().setNullWritable(nullWritable);
×
141
        return this;
×
142
    }
143

144
    @Override
145
    public boolean isFavorPathExtension() {
146
        return favorPathExtension;
×
147
    }
148

149
    @Override
150
    public void setFavorPathExtension(boolean favorPathExtension) {
151
        this.favorPathExtension = favorPathExtension;
×
152
    }
×
153

154
    @Override
155
    public RestResponse favorPathExtension(boolean favorPathExtension) {
156
        setFavorPathExtension(favorPathExtension);
×
157
        return this;
×
158
    }
159

160
    @Override
161
    public boolean isIgnoreUnknownPathExtensions() {
162
        return ignoreUnknownPathExtensions;
×
163
    }
164

165
    @Override
166
    public void setIgnoreUnknownPathExtensions(boolean ignoreUnknownPathExtensions) {
167
        this.ignoreUnknownPathExtensions = ignoreUnknownPathExtensions;
×
168
    }
×
169

170
    @Override
171
    public RestResponse ignoreUnknownPathExtensions(boolean ignoreUnknownPathExtensions) {
172
        setIgnoreUnknownPathExtensions(ignoreUnknownPathExtensions);
×
173
        return this;
×
174
    }
175

176
    @Override
177
    public boolean isIgnoreAcceptHeader() {
178
        return ignoreAcceptHeader;
×
179
    }
180

181
    @Override
182
    public void setIgnoreAcceptHeader(boolean ignoreAcceptHeader) {
183
        this.ignoreAcceptHeader = ignoreAcceptHeader;
×
184
    }
×
185

186
    @Override
187
    public RestResponse ignoreAcceptHeader(boolean ignoreAcceptHeader) {
188
        setIgnoreAcceptHeader(ignoreAcceptHeader);
×
189
        return this;
×
190
    }
191

192
    @Override
193
    public MediaType getDefaultContentType() {
194
        return defaultContentType;
×
195
    }
196

197
    @Override
198
    public void setDefaultContentType(MediaType defaultContentType) {
199
        this.defaultContentType = defaultContentType;
×
200
    }
×
201

202
    @Override
203
    public void setDefaultContentType(String defaultContentType) {
204
        this.defaultContentType = MediaType.parseMediaType(defaultContentType);
×
205
    }
×
206

207
    @Override
208
    public RestResponse defaultContentType(MediaType defaultContentType) {
209
        setDefaultContentType(defaultContentType);
×
210
        return this;
×
211
    }
212

213
    @Override
214
    public RestResponse ok() {
215
        this.status = HttpStatus.OK.value();
×
216
        return this;
×
217
    }
218

219
    @Override
220
    public RestResponse created() {
221
        return created(null);
×
222
    }
223

224
    @Override
225
    public RestResponse created(String location) {
226
        this.status = HttpStatus.CREATED.value();
×
227
        setHeader(HttpHeaders.LOCATION, location);
×
228
        return this;
×
229
    }
230

231
    @Override
232
    public RestResponse accepted() {
233
        this.status = HttpStatus.ACCEPTED.value();
×
234
        return this;
×
235
    }
236

237
    @Override
238
    public RestResponse noContent() {
239
        this.status = HttpStatus.NO_CONTENT.value();
×
240
        return this;
×
241
    }
242

243
    @Override
244
    public RestResponse movedPermanently() {
245
        this.status = HttpStatus.MOVED_PERMANENTLY.value();
×
246
        return this;
×
247
    }
248

249
    @Override
250
    public RestResponse seeOther() {
251
        this.status = HttpStatus.SEE_OTHER.value();
×
252
        return this;
×
253
    }
254

255
    @Override
256
    public RestResponse notModified() {
257
        this.status = HttpStatus.NOT_MODIFIED.value();
×
258
        return this;
×
259
    }
260

261
    @Override
262
    public RestResponse temporaryRedirect() {
263
        this.status = HttpStatus.TEMPORARY_REDIRECT.value();
×
264
        return this;
×
265
    }
266

267
    @Override
268
    public RestResponse badRequest() {
269
        this.status = HttpStatus.BAD_REQUEST.value();
×
270
        return this;
×
271
    }
272

273
    @Override
274
    public RestResponse unauthorized() {
275
        this.status = HttpStatus.UNAUTHORIZED.value();
×
276
        return this;
×
277
    }
278

279
    @Override
280
    public RestResponse forbidden() {
281
        this.status = HttpStatus.FORBIDDEN.value();
×
282
        return this;
×
283
    }
284

285
    @Override
286
    public RestResponse notFound() {
287
        this.status = HttpStatus.NOT_FOUND.value();
×
288
        return this;
×
289
    }
290

291
    @Override
292
    public RestResponse methodNotAllowed() {
293
        this.status = HttpStatus.METHOD_NOT_ALLOWED.value();
×
294
        return this;
×
295
    }
296

297
    @Override
298
    public RestResponse notAcceptable() {
299
        this.status = HttpStatus.NOT_ACCEPTABLE.value();
×
300
        return this;
×
301
    }
302

303
    @Override
304
    public RestResponse conflict() {
305
        this.status = HttpStatus.CONFLICT.value();
×
306
        return this;
×
307
    }
308

309
    @Override
310
    public RestResponse preconditionFailed() {
311
        this.status = HttpStatus.PRECONDITION_FAILED.value();
×
312
        return this;
×
313
    }
314

315
    @Override
316
    public RestResponse unsupportedMediaType() {
317
        this.status = HttpStatus.UNSUPPORTED_MEDIA_TYPE.value();
×
318
        return this;
×
319
    }
320

321
    @Override
322
    public RestResponse internalServerError() {
323
        this.status = HttpStatus.INTERNAL_SERVER_ERROR.value();
×
324
        return this;
×
325
    }
326

327
    @Override
328
    public int getStatus() {
329
        return status;
×
330
    }
331

332
    @Override
333
    public RestResponse setStatus(int status) {
334
        this.status = status;
×
335
        return this;
×
336
    }
337

338
    @Override
339
    public RestResponse setStatus(HttpStatus status) {
340
        Assert.notNull(status, "'status' must not be null");
×
341
        this.status = status.value();
×
342
        return this;
×
343
    }
344

345
    @Override
346
    public RestResponse setHeader(String name, String value) {
347
        if (name == null) {
×
348
            throw new IllegalArgumentException("Header name must not be null");
×
349
        }
350
        touchHeaders().set(name, value);
×
351
        return this;
×
352
    }
353

354
    @Override
355
    public RestResponse addHeader(String name, String value) {
356
        if (name == null) {
×
357
            throw new IllegalArgumentException("Header name must not be null");
×
358
        }
359
        touchHeaders().add(name, value);
×
360
        return this;
×
361
    }
362

363
    protected MultiValueMap<String, String> getHeaders() {
364
        return headers;
×
365
    }
366

367
    private MultiValueMap<String, String> touchHeaders() {
368
        if (headers == null) {
×
369
            headers = new LinkedCaseInsensitiveMultiValueMap<>();
×
370
        }
371
        return headers;
×
372
    }
373

374
    protected abstract List<MediaType> getSupportedContentTypes();
375

376
    protected abstract MediaType getContentTypeByPathExtension(String extension);
377

378
    protected MediaType determineAcceptContentType(@NonNull Activity activity)
379
            throws HttpMediaTypeNotAcceptableException {
380
        if (isFavorPathExtension()) {
×
381
            String path = activity.getTranslet().getRequestName();
×
382
            String ext = FilenameUtils.getExtension(path);
×
383
            if (StringUtils.hasLength(ext)) {
×
384
                ext = ext.toLowerCase(Locale.ENGLISH);
×
385
                MediaType contentType = getContentTypeByPathExtension(ext);
×
386
                if (contentType != null) {
×
387
                    return contentType;
×
388
                }
389
            }
390
            if (!isIgnoreUnknownPathExtensions()) {
×
391
                throw new HttpMediaTypeNotAcceptableException(getSupportedContentTypes());
×
392
            }
393
        }
394
        if (!isIgnoreAcceptHeader()) {
×
395
            List<MediaType> acceptContentTypes = RequestHeaderParser.resolveAcceptContentTypes(activity.getRequestAdapter());
×
396
            for (MediaType contentType : acceptContentTypes) {
×
397
                if (contentType.equalsTypeAndSubtype(MediaType.ALL) &&
×
398
                        getDefaultContentType() != null &&
×
399
                        getSupportedContentTypes().contains(getDefaultContentType())) {
×
400
                    return getDefaultContentType();
×
401
                }
402
                for (MediaType supportedContentType : getSupportedContentTypes()) {
×
403
                    if (contentType.includes(supportedContentType)) {
×
404
                        return contentType;
×
405
                    }
406
                }
×
407
            }
×
408
            if (getSupportedContentTypes().contains(getDefaultContentType())) {
×
409
                return getDefaultContentType();
×
410
            }
411
        }
412
        throw new HttpMediaTypeNotAcceptableException(getSupportedContentTypes());
×
413
    }
414

415
    protected MediaType determineResponseContentType(@NonNull Activity activity, @NonNull MediaType acceptContentType) {
416
        Charset charset = acceptContentType.getCharset();
×
417
        if (charset == null) {
×
418
            String encoding = determineIntendedEncoding(activity);
×
419
            if (encoding != null) {
×
420
                charset = Charset.forName(encoding);
×
421
            }
422
        }
423
        if (charset != null) {
×
424
            return new MediaType(acceptContentType.getType(), acceptContentType.getSubtype(), charset);
×
425
        } else {
426
            return new MediaType(acceptContentType.getType(), acceptContentType.getSubtype());
×
427
        }
428
    }
429

430
    protected String determineIntendedEncoding(@NonNull Activity activity) {
431
        return activity.getTranslet().getDefinitiveResponseEncoding();
×
432
    }
433

434
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc