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

aspectran / aspectran / #4053

10 Feb 2025 01:14PM CUT coverage: 35.271% (-0.02%) from 35.294%
#4053

push

github

topframe
Update

0 of 1 new or added line in 1 file covered. (0.0%)

155 existing lines in 3 files now uncovered.

14245 of 40387 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/DefaultRestResponse.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.core.activity.response.transform.AponTransformResponse;
20
import com.aspectran.core.activity.response.transform.JsonTransformResponse;
21
import com.aspectran.core.activity.response.transform.XmlTransformResponse;
22
import com.aspectran.core.adapter.RequestAdapter;
23
import com.aspectran.core.adapter.ResponseAdapter;
24
import com.aspectran.utils.Assert;
25
import com.aspectran.utils.StringifyContext;
26
import com.aspectran.utils.ToStringBuilder;
27
import com.aspectran.utils.annotation.jsr305.NonNull;
28
import com.aspectran.utils.apon.ObjectToParameters;
29
import com.aspectran.utils.apon.Parameters;
30
import com.aspectran.utils.json.JsonWriter;
31
import com.aspectran.web.support.http.HttpMediaTypeNotAcceptableException;
32
import com.aspectran.web.support.http.HttpStatus;
33
import com.aspectran.web.support.http.MediaType;
34

35
import javax.xml.transform.TransformerException;
36
import java.io.IOException;
37
import java.io.Writer;
38
import java.nio.charset.Charset;
39
import java.util.Collections;
40
import java.util.List;
41
import java.util.Map;
42

43
/**
44
 * The default RestResponse supports APON, JSON, and XML data types.
45
 *
46
 * <p>Created: 2019-06-16</p>
47
 */
48
public class DefaultRestResponse extends AbstractRestResponse {
49

50
    private static final int MAX_INDENT = 8;
51

52
    private static final List<MediaType> supportedContentTypes;
53
    static {
54
        supportedContentTypes = List.of(
×
55
                MediaType.TEXT_PLAIN,
56
                MediaType.TEXT_HTML,
57
                MediaType.APPLICATION_JSON,
58
                MediaType.APPLICATION_APON,
59
                MediaType.APPLICATION_XML);
60
    }
61

62
    private static final Map<String, MediaType> supportedPathExtensions;
63
    static {
64
        supportedPathExtensions = Map.of(
×
65
                "json", MediaType.APPLICATION_JSON,
66
                "apon", MediaType.APPLICATION_APON,
67
                "xml", MediaType.APPLICATION_XML,
68
                "txt", MediaType.TEXT_PLAIN,
69
                "html", MediaType.TEXT_HTML,
70
                "htm", MediaType.TEXT_HTML);
71
    }
×
72

73
    public DefaultRestResponse() {
74
        super();
×
75
    }
×
76

77
    public DefaultRestResponse(Object data) {
78
        super(data);
×
79
    }
×
80

81
    public DefaultRestResponse(String label, Object data) {
82
        super(label, data);
×
83
    }
×
84

85
    @Override
86
    protected List<MediaType> getSupportedContentTypes() {
87
        return supportedContentTypes;
×
88
    }
89

90
    @Override
91
    protected MediaType getContentTypeByPathExtension(String extension) {
92
        return supportedPathExtensions.get(extension);
×
93
    }
94

95
    @Override
96
    public void transform(Activity activity) throws Exception {
97
        Assert.notNull(activity, "activity must not be null");
×
98
        ResponseAdapter responseAdapter = activity.getResponseAdapter();
×
99

100
        MediaType acceptContentType;
101
        try {
102
            acceptContentType = determineAcceptContentType(activity);
×
103
        } catch (HttpMediaTypeNotAcceptableException e) {
×
104
            responseAdapter.setStatus(HttpStatus.NOT_ACCEPTABLE.value());
×
105
            return;
×
106
        }
×
107

108
        MediaType responseContentType = determineResponseContentType(activity, acceptContentType);
×
109
        responseAdapter.setContentType(responseContentType.toString());
×
110

111
        transformByContentType(activity, acceptContentType);
×
112

113
        if (getHeaders() != null) {
×
114
            for (Map.Entry<String, List<String>> entry : getHeaders().entrySet()) {
×
115
                String name = entry.getKey();
×
116
                List<String> values = entry.getValue();
×
117
                for (String value : values) {
×
118
                    responseAdapter.addHeader(name, value);
×
119
                }
×
120
            }
×
121
        }
122

123
        if (getStatus() > 0) {
×
124
            responseAdapter.setStatus(getStatus());
×
125
        }
126
    }
×
127

128
    protected void transformByContentType(Activity activity, MediaType contentType) throws Exception {
129
        if (MediaType.APPLICATION_JSON.equalsTypeAndSubtype(contentType)) {
×
130
            toJSON(activity, parseIndent(contentType));
×
131
        } else if (MediaType.APPLICATION_APON.equalsTypeAndSubtype(contentType)) {
×
132
            toAPON(activity, parseIndent(contentType));
×
133
        } else if (MediaType.APPLICATION_XML.equalsTypeAndSubtype(contentType)) {
×
134
            Charset charset = contentType.getCharset();
×
135
            String encoding = (charset != null ? charset.name() : null);
×
136
            toXML(activity, encoding, parseIndent(contentType));
×
137
        } else {
×
138
            toText(activity);
×
139
        }
140
    }
×
141

142
    private void toJSON(@NonNull Activity activity, int indent) throws IOException {
143
        RequestAdapter requestAdapter = activity.getRequestAdapter();
×
144
        ResponseAdapter responseAdapter = activity.getResponseAdapter();
×
145
        Writer writer = responseAdapter.getWriter();
×
146

147
        // support for jsonp
148
        String callback = requestAdapter.getParameter(JsonTransformResponse.CALLBACK_PARAM_NAME);
×
149
        if (callback != null) {
×
150
            writer.write(callback + JsonTransformResponse.ROUND_BRACKET_OPEN);
×
151
        }
152
        if (getName() != null || getData() != null) {
×
153
            StringifyContext stringifyContext = resolveStringifyContext(activity, indent);
×
154
            JsonWriter jsonWriter = new JsonWriter(writer);
×
155
            jsonWriter.setStringifyContext(stringifyContext);
×
156
            if (getName() != null) {
×
157
                jsonWriter.beginObject();
×
158
                jsonWriter.writeName(getName());
×
159
            }
160
            jsonWriter.writeValue(getData());
×
161
            if (getName() != null) {
×
162
                jsonWriter.endObject();
×
163
            }
164
        }
165
        if (callback != null) {
×
166
            writer.write(JsonTransformResponse.ROUND_BRACKET_CLOSE);
×
167
        }
168
    }
×
169

170
    private void toAPON(Activity activity, int indent) throws IOException {
171
        if (getName() != null || getData() != null) {
×
172
            ResponseAdapter responseAdapter = activity.getResponseAdapter();
×
173
            Writer writer = responseAdapter.getWriter();
×
174
            StringifyContext stringifyContext = resolveStringifyContext(activity, indent);
×
175

176
            Parameters parameters;
177
            if (getName() != null) {
×
178
                parameters = ObjectToParameters.from(getName(), getData(), stringifyContext);
×
179
            } else {
180
                parameters = ObjectToParameters.from(getData(), stringifyContext);
×
181
            }
182

183
            AponTransformResponse.transform(parameters, writer, stringifyContext);
×
184
        }
185
    }
×
186

187
    private void toXML(Activity activity, String encoding, int indent) throws IOException, TransformerException {
188
        if (getName() != null || getData() != null) {
×
189
            ResponseAdapter responseAdapter = activity.getResponseAdapter();
×
190
            Writer writer = responseAdapter.getWriter();
×
191
            StringifyContext stringifyContext = resolveStringifyContext(activity, indent);
×
192

193
            Object data;
194
            if (getName() != null) {
×
195
                data = Collections.singletonMap(getName(), getData());
×
196
            } else {
197
                data = getData();
×
198
            }
199
            XmlTransformResponse.transform(data, writer, encoding, stringifyContext);
×
200
        }
201
    }
×
202

203
    private void toText(Activity activity) throws IOException {
204
        if (getName() != null || getData() != null) {
×
205
            ResponseAdapter responseAdapter = activity.getResponseAdapter();
×
206
            Writer writer = responseAdapter.getWriter();
×
207
            if (getData() != null) {
×
208
                writer.write(ToStringBuilder.toString(getName(), getData()));
×
209
            }
210
        }
211
    }
×
212

213
    @NonNull
214
    private StringifyContext resolveStringifyContext(@NonNull Activity activity, int indent) {
215
        StringifyContext stringifyContext = getStringifyContext();
×
216
        if (stringifyContext == null) {
×
217
            stringifyContext = activity.getStringifyContext().clone();
×
218
        } else {
219
            stringifyContext.merge(activity.getStringifyContext());
×
220
        }
UNCOV
221
        if (stringifyContext.isPretty() && !stringifyContext.hasIndentSize() && indent > -1) {
×
222
            stringifyContext.setIndentSize(indent);
×
223
        }
UNCOV
224
        return stringifyContext;
×
225
    }
226

227
    private int parseIndent(@NonNull MediaType contentType) {
228
        try {
229
            String indent = contentType.getParameter("indent");
×
230
            if (indent != null) {
×
UNCOV
231
                int depth = Integer.parseInt(indent);
×
232
                return (Math.min(depth, MAX_INDENT));
×
233
            }
234
        } catch (NumberFormatException e) {
×
235
            // ignored
UNCOV
236
        }
×
UNCOV
237
        return -1;
×
238
    }
239

240
}
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