Skip to content

Commit 942cf75

Browse files
authored
Merge pull request #857 from b2ihealthcare/improvement/SO-4890-support-includeNull-pretty-query-parameters
SO- 4890: support includeNull and pretty query parameters
2 parents b90b120 + b69b88a commit 942cf75

File tree

2 files changed

+64
-6
lines changed
  • core/com.b2international.snowowl.core.rest/src/com/b2international/snowowl/core/rest
  • fhir/com.b2international.snowowl.fhir.rest.tests/src/com/b2international/snowowl/fhir/tests

2 files changed

+64
-6
lines changed

core/com.b2international.snowowl.core.rest/src/com/b2international/snowowl/core/rest/SnowOwlApiConfig.java

+63-5
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@
1717

1818
import java.lang.reflect.AnnotatedElement;
1919
import java.lang.reflect.Method;
20+
import java.util.BitSet;
2021
import java.util.List;
2122
import java.util.Map;
2223
import java.util.TimeZone;
2324
import java.util.function.Predicate;
25+
import java.util.stream.Stream;
2426

2527
import javax.servlet.http.HttpServletRequest;
2628

@@ -77,6 +79,9 @@
7779
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
7880
import com.google.common.base.Charsets;
7981
import com.google.common.base.Strings;
82+
import com.google.common.cache.CacheBuilder;
83+
import com.google.common.cache.CacheLoader;
84+
import com.google.common.cache.LoadingCache;
8085
import com.google.common.collect.ImmutableMap;
8186
import com.google.inject.Provider;
8287

@@ -94,20 +99,34 @@
9499
@PropertySource("classpath:com/b2international/snowowl/core/rest/service_configuration.properties")
95100
public class SnowOwlApiConfig extends WebMvcConfigurationSupport {
96101

102+
private static final String INCLUDE_NULL = "includeNull";
103+
private static final int INCLUDE_NULL_IDX = 0;
104+
private static final String PRETTY = "pretty";
105+
private static final int PRETTY_IDX = 1;
106+
97107
static {
98108
SpringDocUtils.getConfig().addResponseWrapperToIgnore(Promise.class);
99109
}
100110

101111
@Autowired
102112
private org.springframework.context.ApplicationContext ctx;
103113

114+
private final LoadingCache<BitSet, ObjectMapper> objectMappers = CacheBuilder.newBuilder().build(new CacheLoader<BitSet, ObjectMapper>() {
115+
@Override
116+
public ObjectMapper load(BitSet configuration) throws Exception {
117+
ObjectMapper mapper = createObjectMapper();
118+
mapper.setSerializationInclusion(configuration.get(INCLUDE_NULL_IDX) ? Include.ALWAYS : Include.NON_NULL);
119+
mapper.configure(SerializationFeature.INDENT_OUTPUT, configuration.get(PRETTY_IDX));
120+
return mapper;
121+
}
122+
});
123+
104124
@Bean
105125
public OpenAPI openAPI() {
106126
return new OpenAPI();
107127
}
108128

109-
@Bean
110-
public ObjectMapper objectMapper() {
129+
public static ObjectMapper createObjectMapper() {
111130
final ObjectMapper objectMapper = new ObjectMapper();
112131
objectMapper.registerModule(new JavaTimeModule());
113132
objectMapper.setSerializationInclusion(Include.NON_NULL);
@@ -120,6 +139,42 @@ public ObjectMapper objectMapper() {
120139
return objectMapper;
121140
}
122141

142+
@Bean
143+
@Scope(scopeName = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
144+
public ObjectMapper objectMapper(@Autowired HttpServletRequest request) {
145+
return objectMappers.getUnchecked(toConfig(
146+
extractBooleanQueryParameterValue(request, INCLUDE_NULL),
147+
extractBooleanQueryParameterValue(request, PRETTY)
148+
));
149+
}
150+
151+
private BitSet toConfig(boolean...serializationFeatureValuesInOrder) {
152+
if (serializationFeatureValuesInOrder == null) {
153+
return new BitSet(0);
154+
}
155+
BitSet config = new BitSet(serializationFeatureValuesInOrder.length);
156+
for (int i = 0; i < serializationFeatureValuesInOrder.length; i++) {
157+
config.set(i, serializationFeatureValuesInOrder[i]);
158+
}
159+
return config;
160+
}
161+
162+
private boolean extractBooleanQueryParameterValue(HttpServletRequest request, String queryParameterKey) {
163+
String[] values = request.getParameterMap().containsKey(queryParameterKey) ? request.getParameterMap().getOrDefault(queryParameterKey, null) : null;
164+
if (values == null) {
165+
// query parameter not present, means disable feature
166+
return false;
167+
} else if (values.length == 0) {
168+
// no values present, but the key is present, enable feature
169+
return true;
170+
} else {
171+
// XXX due to a bug in jetty-server v9.x, query parameters are duplicated in the low-level request object
172+
// allowing multiple values for now with empty or valid (true in this case) values here
173+
// see this bug report for details https://github.com/eclipse/jetty.project/issues/2074
174+
return Stream.of(values).allMatch(value -> value.isBlank() || "true".equals(value));
175+
}
176+
}
177+
123178
@Override
124179
protected void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
125180
returnValueHandlers.add(new PromiseMethodReturnValueHandler());
@@ -204,10 +259,13 @@ public void configureMessageConverters(final List<HttpMessageConverter<?>> conve
204259
converters.add(new ByteArrayHttpMessageConverter());
205260
converters.add(new ResourceHttpMessageConverter());
206261
converters.add(new CsvMessageConverter());
262+
// XXX using null value here as Spring calls a proxied method anyway which returns an already configured instance, see mapping2JacksonHttpMessageConverter Bean method
263+
converters.add(mapping2JacksonHttpMessageConverter(null));
264+
}
207265

208-
final MappingJackson2HttpMessageConverter jacksonConverter = new MappingJackson2HttpMessageConverter();
209-
jacksonConverter.setObjectMapper(objectMapper());
210-
converters.add(jacksonConverter);
266+
@Bean
267+
public MappingJackson2HttpMessageConverter mapping2JacksonHttpMessageConverter(ObjectMapper mapper) {
268+
return new MappingJackson2HttpMessageConverter(mapper);
211269
}
212270

213271
@Override

fhir/com.b2international.snowowl.fhir.rest.tests/src/com/b2international/snowowl/fhir/tests/FhirTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public class FhirTest {
3939

4040
protected static final String TEST_DATE_STRING = "2018-03-23T07:49:40.000+0000"; //$NON-NLS-N$
4141

42-
protected static final ObjectMapper objectMapper = new SnowOwlApiConfig().objectMapper();
42+
protected static final ObjectMapper objectMapper = SnowOwlApiConfig.createObjectMapper();
4343

4444
@Rule
4545
public ExpectedException exception = ExpectedException.none();

0 commit comments

Comments
 (0)