elm: decode json that contains a json array - elm

So I need to decode a json that contains a json array in elm. Here is my model:
type alias ValidationResult =
{ parameter : String
, errorMessage : String
}
type alias ErrorResponse =
{ validationErrors : List ValidationResult }
And here is an example of the json:
{"ValidationErrors": [{"Parameter": "param1","ErrorMessage": "message 1"},{"Parameter": "param2","ErrorMessage": "error message 2"}]}
I've tried to create a ValidationResult decoder, like:
decodeValidationResults : Decoder ValidationResult
decodeValidationResults =
map2 ValidationResult
(at [ "Parameter" ] Json.Decode.string)
(at [ "ErrorMessage" ] Json.Decode.string)
But I don't know how to proceed further.
I am using elm 0.18

You are almost there! You just need a decoder that decodes the ErrorResponse type. To do so, create another decoder that uses a list of the decoder you've already created, assuming the field name is "ValidationErrors":
import Json.Decode exposing (..)
decodeErrorResponse : Decoder ErrorResponse
decodeErrorResponse =
map ErrorResponse
(field "ValidationErrors" (list decodeValidationResults))
One bit of advice: You can use Json.Decode.field instead of Json.Decode.at when there is only a single level. You can rewrite decodeValidationResults as this:
decodeValidationResults : Decoder ValidationResult
decodeValidationResults =
map2 ValidationResult
(field "Parameter" string)
(field "ErrorMessage" string)

Related

Kotlin: Type inference failed. The value of the type parameter T should be mentioned in input types

I'm new to Kotlin, for the piece of the below code:
fun a(stcd: String) {
val res = mutableSetOf<String>()
val aaa = mutableListOf<Map<String, Set<String>>>()
aaa.stream().filter { x: Map<String, Set<String>> -> x.isNotEmpty() }
.filter { x: Map<String, Set<String>> ->
x.values.contains(stcd) // throws error
}.forEach { x: Map<String, Set<String>> ->
x.forEach { (k: String, v: Set<String>?) ->
res.add(k)
}
}
}
Could anyone point out why contains throws error:Type inference failed. The value of the type parameter T should be mentioned in input types (argument types, receiver type or expected type). Try to specify it explicitly.?
This is because x.values is not a Set<String>, as you probably think it is. In fact, it's aCollection<Set<String>> as per the definition of values. So, such a collection can't contain a String type.

Spring Hateoas: EntityModel _links rendered before content

This is a weird problem to describe since it's no actually a problem in the technical sense but still makes me curious enough to ask about it:
I created a #RestController that returns ResponseEntity<EntityModel<?>>. I build the EntityModel and attach a self link built with linkTo and methodOn. Now for some reason, the output looks like this:
{
"_links" : {
"self" : {
"href" : "http://localhost:8080/points/knx/office_light"
}
},
"labels" : {
"name" : "Light",
"room" : "Office"
},
"access" : [ "READ", "WRITE" ],
"type" : "SwitchPoint",
"state" : "OFF"
}
Contrary to other rest services I have build, the "_link" gets rendered at the top not at the bottom. Any ideas why?
#GetMapping("{ext}/{id}")
public ResponseEntity<EntityModel<Map<String, Object>>> oneByExt(#PathVariable String ext,
#PathVariable String id) {
EntityModel<Map<String, Object>> point = client.getPoint(ext, id);
return new ResponseEntity<>(localToGlobal(ext, point), HttpStatus.OK);
}
private <T> EntityModel<T> localToGlobal(String ext, EntityModel<T> model) {
ComposedId id = ComposedId.fromEntityModel(ext, model);
Link newSelfLink = linkTo(methodOn(PointController.class).oneByExt(id.getExtension(), id.getIdentifier()))
.withSelfRel();
EntityModel<T> newModel = EntityModel.of(model.getContent());
newModel.add(newSelfLink);
return newModel;
}
It's probably due to the Map, I'm assuming you using something like HashMap which has no guarantee of iteration order. Try change it to a LinkedHashMap and see what happens (should print the values in the order they were added to the map)

Convert JSON string to Map with any primitive type or JSONObject

I am trying to convert provided string (JSON) to Map<String,Any> so for example JSON can be like that (value can be any primitive type or a collection such as map set or array :
{
"key": "thisIsMyKey",
"value": false
}
So i did convert it using GSON with this little snippet:
return jsonMap?.let { Gson().fromJson(jsonMap, object : TypeToken<HashMap<String, Any>>() {}.type) }
The issue i am having is now for following example if i want to pass value with JSONObject
{
"key": "thisIsMyKey",
"value": {
"title": "this is title"
}
}
It gets converted to one key and multiple "Any" values with string, but in this case i expect that value is than just one entry of <String, JSONObject), any tips how to achieve this one level too deep converting?
You may do this by specifying expected type as Map<String, JsonElement>. Downside of this approach is that values of primitive types (Number, String, Boolean) would be wrapped into JsonPrimitive. If it's unacceptable, you may manually unwrap them:
val result = jsonMap?.let {
Gson().fromJson<Map<String, JsonElement>>(jsonMap).mapValues { (_, v) -> deprimitivize(v) }
}
fun deprimitivize(e: JsonElement) = if (e is JsonPrimitive) e.getValue() else e
fun JsonPrimitive.getValue(): Any = when {
isBoolean -> asBoolean
isNumber -> asNumber
else -> asString
}
inline fun <reified T : Any> Gson.fromJson(json: String): T = fromJson(json, object : TypeToken<T>() {}.type)

Spring Data with ReactiveMongoRepository: generic saving

I would like to save some documents with the value containing a generic. And I constantly receive a StackOferflowError.
Here is a fragment of my model class
data class MyDocument {
val errors: List<SomeError> = emptyList()
}
SomeError is in interface that should be implemented by different types of errors including ValidationError
interface SomeError
data class ValidationError<T: Any>(val objectType: KClass<T>, val objectId: String) : SomeError
I am trying to save my object with non-empty list of errors (using ReactiveMongoRespoitory):
myDocumentRepository.save(MyDocument(
errors = listOf(
ValidationError<MyDocument>(objectType = MyDocument::class, objectId = "somedoc")) //as SomeError did not help
))
Do you know how I can correct it?
This is a psrt of the Stack trace:
java.lang.StackOverflowError
at java.base/java.util.HashMap.putVal(HashMap.java:624)
at java.base/java.util.HashMap.putMapEntries(HashMap.java:510)
at java.base/java.util.HashMap.putAll(HashMap.java:780)
at org.springframework.data.util.TypeDiscoverer.resolveType(TypeDiscoverer.java:168)
at org.springframework.data.util.ParameterizedTypeInformation.calculateTypeVariables(ParameterizedTypeInformation.java:269)
You can do something like this:
import org.springframework.data.annotation.Transient
data class ValidationError private constructor(
private val type: String,
val objectId: String
) : SomeError {
constructor(type: KClass<*>, objectId: String) : this(type.qualifiedName!!, objectId)
#delegate:Transient
val objectType by lazy {
this.javaClass.classLoader.loadClass(type).kotlin
}
}
Store KClass internally as fully qualified name.

Jackson cannot deserialize some non-empty fields

I have a problem with the object deserialization.
My DTO contains a list of Pairs (the previous version was Map).
data class MyDto(
#JsonIgnoreProperties(ignoreUnknown = true)
val myField: List<Pair<String, Boolean>>?
)
And I constantly receive a MissingKotlinParameterException
com.fasterxml.jackson.module.kotlin.MissingKotlinParameterException: Instantiation of [simple type, class kotlin.Pair<java.lang.String,java.lang.Boolean>] value failed for JSON property first due to missing (therefore NULL) value for creator parameter first which is a non-nullable type\n at [Source: (io.netty.buffer.ByteBufInputStream); line: 9, column: 33] (through reference chain: my.path.MyDto[\"field\"]->java.util.ArrayList[0]->kotlin.Pair[\"first\"])\n\tat org.springframework.http.codec.json.AbstractJackson2Decoder.processException(AbstractJackson2Decoder.java:162)
my json looks like:
{
"myField" : [
"A": true,
"B": false
]
}
As you can see I have already made the list nullable and put an annotation#JsonIgnoreProperties. But still I get the error.
My configuration for the objectMapper
#Bean
#Primary
fun objectMapper(): ObjectMapper = jacksonObjectMapper().apply {
findAndRegisterModules()
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.disable(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS)
.disable(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES)
.disable(DeserializationFeature.FAIL_ON_NULL_CREATOR_PROPERTIES)
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
.disable(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT)
.disable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT)
.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
.enable(DeserializationFeature.ACCEPT_FLOAT_AS_INT)
}
What should I also enable/disable to make it work?
Try replacing
List<Pair<String, Boolean>>
with
Map<String, Boolean>
And change the JSON to:
{
"myField" : {
"A": true,
"B": false
}
}
Should work as intended now.