Skip to content

Instantly share code, notes, and snippets.

@duergner
Created March 8, 2017 06:41
Show Gist options
  • Save duergner/fb2e9a81faf5ab833ae9a24c99ff8c2f to your computer and use it in GitHub Desktop.
Save duergner/fb2e9a81faf5ab833ae9a24c99ff8c2f to your computer and use it in GitHub Desktop.
A very minimalistic configuration showing how zalando-incubator/json-fields can be used with a Spring Boot application
package org.zalando.demo.boot.jsonfields;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Supplier;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.zalando.guild.api.json.fields.jackson.JsonFieldsModule;
import org.zalando.guild.api.json.fields.jackson.ThreadLocalContextProvider;
import org.zalando.guild.api.json.fields.java.expression.ParserFramework;
import org.zalando.guild.api.json.fields.java.model.FieldPredicate;
import org.zalando.guild.api.json.fields.java.model.FieldPredicates;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
import java.util.List;
@SpringBootApplication
public class JsonFieldsApplication {
@Configuration
static final class WebMvcConfiguration extends WebMvcConfigurerAdapter {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(mappingJackson2HttpMessageConverter());
}
@Bean
public FilterRegistrationBean fieldsFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new FieldsFilter());
registration.addUrlPatterns("/*");
registration.setName("fieldsFilter");
return registration;
}
private MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
ObjectMapper objectMapper = new Jackson2ObjectMapperBuilder()
.modules(
JsonFieldsModule.createJsonFieldsModule(
FieldsFilter.FIELD_PREDICATE_SUPPLIER,
ThreadLocalContextProvider.getInstance()))
.build();
jsonConverter.setObjectMapper(objectMapper);
return jsonConverter;
}
/**
* A plain Servlet Filter that will parse the configured parameter from the incoming request and
* expose it afterwards via a {@link ThreadLocal} variable.
*/
static final class FieldsFilter implements Filter {
/**
* {@link ThreadLocal} based implementation for a {@link Supplier<FieldPredicate>} as
* needed by
* the <i>json-fields</i> library
*/
public static final Supplier<FieldPredicate> FIELD_PREDICATE_SUPPLIER = new Supplier<FieldPredicate>() {
@Override
public FieldPredicate get() {
return FIELD_PREDICATE.get();
}
};
/**
* Default filter which will not alter the original reponse
*/
private static final FieldPredicate DEFAULT_FIELDS_PREDICATE = FieldPredicates.alwaysTrue();
/**
* {@link ThreadLocal} variable which holds the parsed filter expression
*/
private static final ThreadLocal<FieldPredicate> FIELD_PREDICATE = new InheritableThreadLocal<FieldPredicate>() {
@Override
protected FieldPredicate initialValue() {
return DEFAULT_FIELDS_PREDICATE;
}
};
private final String parameter;
public FieldsFilter() {
this("fields");
}
public FieldsFilter(String parameter) {
this.parameter = parameter;
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(
ServletRequest servletRequest,
ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
final String fields = servletRequest.getParameter(parameter);
if (fields == null || fields.isEmpty()) {
FIELD_PREDICATE.set(DEFAULT_FIELDS_PREDICATE);
} else {
try {
final FieldPredicate fieldsExpression = ParserFramework.parseFieldsExpression(fields);
FIELD_PREDICATE.set(fieldsExpression);
} catch (RuntimeException ignore) {
FIELD_PREDICATE.set(DEFAULT_FIELDS_PREDICATE);
}
}
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment