Commit 6c61ed71 authored by Matija Obreza's avatar Matija Obreza

Cache serialized JSON of /api/v1/crops

- Using Google cache to prevent concurrent calls to the service
- Serialization of objects takes a long time
parent 1f670cc7
......@@ -18,6 +18,8 @@ package org.genesys2.server.api.v1;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import org.genesys.blocks.model.JsonViews;
import org.genesys.filerepository.InvalidRepositoryPathException;
......@@ -30,6 +32,7 @@ import org.genesys2.server.model.impl.CropRule;
import org.genesys2.server.model.impl.CropTaxonomy;
import org.genesys2.server.service.CRMException;
import org.genesys2.server.service.CropService;
import org.genesys2.server.service.CropService.CropDetails;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.data.domain.Page;
......@@ -42,9 +45,19 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.fasterxml.jackson.annotation.JsonView;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module;
import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module.Feature;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import io.swagger.annotations.Api;
import net.sf.oval.ConstraintViolation;
......@@ -62,16 +75,50 @@ public class CropsController extends ApiBaseController {
@Autowired
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
private static ObjectMapper objectMapper;
static {
objectMapper = new ObjectMapper();
Hibernate5Module hibernateModule = new Hibernate5Module();
hibernateModule.disable(Feature.FORCE_LAZY_LOADING);
hibernateModule.disable(Feature.SERIALIZE_IDENTIFIER_FOR_LAZY_NOT_LOADED_OBJECTS);
objectMapper.registerModule(hibernateModule);
// serialization
objectMapper.disable(SerializationFeature.EAGER_SERIALIZER_FETCH);
// deserialization
objectMapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
// // Never ignore stuff we don't understand
// mapper.enable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
// ignore stuff we don't understand
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
// explicit json views: every fields needs to be annotated, therefore enabled
objectMapper.enable(MapperFeature.DEFAULT_VIEW_INCLUSION);
// enable upgrading to arrays
objectMapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
}
private final Cache<String, String> cacheCropDetails = CacheBuilder.newBuilder().maximumSize(5).expireAfterWrite(5, TimeUnit.MINUTES).build();
/**
* List of Crop details
*
* @return list of crop details
* @throws JsonProcessingException
* @throws ExecutionException
*/
@RequestMapping(value = "", method = RequestMethod.GET, produces = { MediaType.APPLICATION_JSON_VALUE })
public List<CropService.CropDetails> listCropDetails() {
LOG.info("Listing crop details");
return cropService.listDetails(LocaleContextHolder.getLocale());
public @ResponseBody String listCropDetails() throws JsonProcessingException, ExecutionException {
return cacheCropDetails.get("api-v1-crops", () -> {
LOG.info("Listing crop details");
List<CropDetails> crops = cropService.listDetails(LocaleContextHolder.getLocale());
LOG.debug("Got crops");
String json = objectMapper.writeValueAsString(crops);
LOG.debug("Serialized to JSON");
return json;
});
}
/**
......
......@@ -16,6 +16,7 @@
package org.genesys2.spring.config;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Set;
......@@ -39,6 +40,7 @@ import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.http.CacheControl;
import org.springframework.http.MediaType;
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
......@@ -63,6 +65,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module;
import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module.Feature;
import com.google.common.base.Charsets;
/**
* Spring MVC
......@@ -261,16 +264,22 @@ public class WebConfiguration implements WebMvcConfigurer {
return mapper;
}
public StringHttpMessageConverter stringConverter() {
final StringHttpMessageConverter stringConverter = new StringHttpMessageConverter(Charsets.UTF_8);
stringConverter.setSupportedMediaTypes(Arrays.asList(MediaType.TEXT_PLAIN, MediaType.TEXT_HTML, MediaType.APPLICATION_JSON));
return stringConverter;
}
@Override
public void configureMessageConverters(final List<HttpMessageConverter<?>> converters) {
// String-type returns get written directly
converters.add(stringConverter());
// Here we add our custom-configured HttpMessageConverter
converters.add(jacksonMessageConverter());
// Custom CSV converter
converters.add(new CSVMessageConverter<Object>(objectMapper()));
// Raw request body -- needed for uploading raw files
converters.add(new ByteArrayHttpMessageConverter());
// HTTP string
converters.add(new StringHttpMessageConverter());
}
}
package org.genesys.test.config;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
......@@ -39,6 +40,7 @@ import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
......@@ -62,6 +64,8 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module;
import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module.Feature;
import com.google.common.base.Charsets;
public final class ApplicationConfig {
......@@ -272,18 +276,23 @@ public final class ApplicationConfig {
return mapper;
}
public StringHttpMessageConverter stringConverter() {
final StringHttpMessageConverter stringConverter = new StringHttpMessageConverter(Charsets.UTF_8);
stringConverter.setSupportedMediaTypes(Arrays.asList(MediaType.TEXT_PLAIN, MediaType.TEXT_HTML, MediaType.APPLICATION_JSON));
return stringConverter;
}
@Override
public void configureMessageConverters(final List<HttpMessageConverter<?>> converters) {
// HTTP string
converters.add(stringConverter());
// Here we add our custom-configured HttpMessageConverter
converters.add(jacksonMessageConverter());
// Custom CSV converter
converters.add(new CSVMessageConverter<Object>(objectMapper()));
// Raw request body -- needed for uploading raw files
converters.add(new ByteArrayHttpMessageConverter());
// HTTP string
converters.add(new StringHttpMessageConverter());
super.configureMessageConverters(converters);
}
}
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment