1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package eu.ehri.extension.providers;
21
22 import com.fasterxml.jackson.core.JsonParseException;
23 import com.fasterxml.jackson.core.type.TypeReference;
24 import com.fasterxml.jackson.databind.JsonMappingException;
25 import com.fasterxml.jackson.databind.ObjectReader;
26 import com.fasterxml.jackson.databind.ObjectWriter;
27 import com.fasterxml.jackson.dataformat.csv.CsvGenerator;
28 import com.fasterxml.jackson.dataformat.csv.CsvMapper;
29 import com.fasterxml.jackson.dataformat.csv.CsvParser;
30 import com.fasterxml.jackson.dataformat.csv.CsvSchema;
31 import eu.ehri.extension.base.AbstractResource;
32 import eu.ehri.extension.errors.WebDeserializationError;
33 import eu.ehri.project.utils.Table;
34 import eu.ehri.project.exceptions.DeserializationError;
35
36 import javax.ws.rs.Consumes;
37 import javax.ws.rs.Produces;
38 import javax.ws.rs.WebApplicationException;
39 import javax.ws.rs.core.MediaType;
40 import javax.ws.rs.core.MultivaluedMap;
41 import javax.ws.rs.ext.MessageBodyReader;
42 import javax.ws.rs.ext.MessageBodyWriter;
43 import javax.ws.rs.ext.Provider;
44 import java.io.IOException;
45 import java.io.InputStream;
46 import java.io.OutputStream;
47 import java.lang.annotation.Annotation;
48 import java.lang.reflect.Type;
49 import java.util.List;
50
51
52
53
54
55
56 @Provider
57 @Produces({MediaType.APPLICATION_JSON, AbstractResource.CSV_MEDIA_TYPE})
58 @Consumes({MediaType.APPLICATION_JSON, AbstractResource.CSV_MEDIA_TYPE})
59 public class TableProvider implements MessageBodyWriter<Table>, MessageBodyReader<Table>, JsonMessageBodyHandler {
60
61 private static CsvMapper csvMapper = new CsvMapper()
62 .enable(CsvGenerator.Feature.STRICT_CHECK_FOR_QUOTING)
63 .enable(CsvParser.Feature.WRAP_AS_ARRAY);
64 private static CsvSchema csvSchema = csvMapper.schemaFor(List.class);
65
66 private static TypeReference<List<List<String>>> typeRef = new TypeReference<List<List<String>>>() {
67 };
68
69 @Override
70 public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
71 return Table.class.equals(type);
72 }
73
74 @Override
75 public long getSize(Table table, Class<?> aClass, Type type, Annotation[] annotations,
76 MediaType mediaType) {
77 return -1L;
78 }
79
80 @Override
81 public void writeTo(Table table,
82 Class<?> aClass, Type type, Annotation[] annotations,
83 MediaType mediaType, MultivaluedMap<String, Object> headers,
84 OutputStream outputStream) throws IOException, WebApplicationException {
85 ObjectWriter writer = mediaType.isCompatible(MediaType.APPLICATION_JSON_TYPE)
86 ? mapper.writer()
87 : csvMapper.writer(csvSchema.withoutHeader());
88 writer.writeValue(outputStream, table.rows());
89 }
90
91 @Override
92 public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
93 return Table.class.equals(type);
94 }
95
96 @Override
97 public Table readFrom(Class<Table> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException, WebApplicationException {
98 try {
99 ObjectReader reader = mediaType.isCompatible(MediaType.APPLICATION_JSON_TYPE)
100 ? mapper.readerFor(typeRef)
101 : csvMapper.readerFor(typeRef).with(csvSchema.withoutHeader());
102 return Table.of(reader.readValue(entityStream));
103 } catch (JsonMappingException | JsonParseException e) {
104 throw new WebDeserializationError(new DeserializationError(
105 "Deserialization error for media type: " + mediaType, e));
106 }
107 }
108 }