Skip to content

Commit cef8cc5

Browse files
committed
TEMPORARY FIX: allow "values" to by of type array or object in input api
- this is to conform with the old api - the old api accepted the value (no error), but didn't store what was expected: "value": [1,2,true] stored "value": "true" ... - here, at least we both accept AND store the correct value
1 parent 0ae9eaa commit cef8cc5

3 files changed

Lines changed: 49 additions & 2 deletions

File tree

src/main/kotlin/ch/derlin/bbdata/input/InputController.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,10 @@ class InputController(
8585
@PostMapping("objects/values")
8686
@Operation(description = "Submit new measures. " +
8787
"Each objectId/timestamp couple must be unique, both in the body and the database. Hence, any duplicate will make the request fail. " +
88-
"If you omit to provide a timestamp for any measure, it will be added automatically (server time). " +
89-
"This request is *atomic*: either *all* measures are valid and saved, or none. ")
88+
"This request is *atomic*: either *all* measures are valid and saved, or none. " +
89+
"If you omit to provide a timestamp for any measure, it will be added automatically (server time).<br><br>" +
90+
"In general, it is better to always enclose the value in quotes. DO NOT send arrays or objects without enclosing quotes, " +
91+
"but serialize them on the collector in order to avoid surprises !")
9092
fun postNewMeasures(@Valid @NotNull @RequestBody rawMeasures: ValidatedList<NewValue>,
9193
@RequestParam("simulate", defaultValue = "false") sim: Boolean): List<NewValueAugmented> {
9294

src/main/kotlin/ch/derlin/bbdata/input/NewValue.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package ch.derlin.bbdata.input
33
import ch.derlin.bbdata.common.cassandra.RawValue
44
import ch.derlin.bbdata.common.cassandra.RawValuePK
55
import ch.derlin.bbdata.common.truncate
6+
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
67
import org.joda.time.DateTime
78
import org.joda.time.YearMonth
89
import javax.validation.constraints.Min
@@ -30,6 +31,7 @@ data class NewValue(
3031

3132
@field:NotNull
3233
@field:NotEmpty
34+
@field:JsonDeserialize(using = RawStringDeserializer::class)
3335
var value: String? = null,
3436

3537
@field:Size(max = 1024, message = "too long. Maximum set to 1024.")
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package ch.derlin.bbdata.input
2+
3+
import com.fasterxml.jackson.core.JsonParser
4+
import com.fasterxml.jackson.databind.DeserializationContext
5+
import com.fasterxml.jackson.databind.JsonDeserializer
6+
import com.fasterxml.jackson.databind.JsonNode
7+
import com.fasterxml.jackson.databind.ObjectMapper
8+
9+
10+
/**
11+
*
12+
* Problem: in the old api, people got used to send arrays or objects as "value",
13+
* while new version is expecting a string.
14+
*
15+
* This mapper always deserialize into strings.
16+
* The behavior is the same for values enclosed in quotes or basic values, it only changes for
17+
* raw arrays ("value": [...]) or objects (e.g. "value": {...}).
18+
*
19+
* Example:
20+
* - "value": [1, 2, false ] => "[1,2,false]"
21+
* - "value": {"a": 1, "b" : "x"} => "{\"a\":1,\"b\":\"x\"}",
22+
* - "value": "[1, 2,false]" => "[1, 2,false]"
23+
* - "value": 1 => "1.0"
24+
*
25+
* BEWARE: if not using quotes, the array or object MUST BE A CORRECT json array/object
26+
*
27+
* date: 30.09.20
28+
* @author Lucy Linder <lucy.derlin@gmail.com>
29+
*/
30+
class RawStringDeserializer : JsonDeserializer<String?>() {
31+
32+
// basic objectMapper: no prettyPrint, nothing...
33+
private val objectMapper = ObjectMapper()
34+
35+
override fun deserialize(p: JsonParser, ctxt: DeserializationContext?): String? {
36+
// use default objectMapper for deserialization, so we keep the usual settings
37+
val node: JsonNode = (if (p.codec is ObjectMapper) p.codec else objectMapper).readTree(p)
38+
// Do not use the default objectMapper for serialization
39+
// since it may be configured with prettyPrint = true
40+
val ret = if (node.isTextual) node.asText() else objectMapper.writeValueAsString(node)
41+
return ret
42+
}
43+
}

0 commit comments

Comments
 (0)