I need to parse a json file like this:
This is a sample mapping file for a collection of my elasticsearch engine server.
{
"mappings":
{
"documents" :
{
"_all" : {"enabled" : false},
"properties" :
{
"user_id" :
{
"type" : "string",
"index" : "not_analyzed",
"store": "no"
},
"mime_type" :
{
"type" : "string",
"index" : "not_analyzed",
"store": "no"
},
"source" :
{
"type" : "string",
"index": "not_analyzed",
"store": "no"
}
}
}
}
}
As you could be figuring out the schema is like that:
{
"mapping":
{
"**collection_name**":
{
...,
"properties":
{
"**property_name_1**":
{
"type": "string|int|date...",
...
},
"**property_name_2**":
{
"type": "string|int|date...",
...
},
...
}
}
}
}
And I would need to map this json to something like these classes:
public class Mapping {
private String collection;
private List<Property> properties;
public Mapping()
{
this.collection = null;
this.properties = new ArrayList<Property>();
}
...
}
public class Property
{
private String property;
private String type;
}
I've no idea how to do it with jackson.
Could you help me please? Thanks for all.
This is how you can do it with jackson:
ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode;
try {
rootNode = mapper.readValue(jsonText, JsonNode.class);
JsonNode mappingsNode = rootNode.get("mappings");
String collectionName = mappingsNode.getFieldNames().next();
JsonNode collectionNode = mappingsNode.get(collectionName);
JsonNode propertiesNode = collectionNode.get("properties");
Iterator<JsonNode> elements = propertiesNode.getElements();
while (elements.hasNext()) {
JsonNode propertyNode = (JsonNode) elements.next();
// get properties one by one
}
} catch (IOException e) {
throw new RuntimeException("error while reading value", e);
}
Code is not completed by it presents the idea. Tested with jackson 1.8.0
Related
I can get all documents from firebase with get() method which is not getting updates from Firestore but I can't get all documents with addSnapshotListener method. When I try to use this method it's throwing following exception :
Invalid document reference. Document references must have an even number of segments, but Pairs has 1
Here is the code snippets :
with snapshot listener :
fun retrievePairsFromFirebase() {
database.collection("Pairs").document(currentUserEmail!!).collection("Pair").addSnapshotListener { value, error ->
if (error != null) {
println(error.localizedMessage)
} else {
value!!.documents.forEach { documentSnapshot ->
if (documentSnapshot.exists()) {
val retreivedObj = documentSnapshot.toObject(PairListModel::class.java)
pairState.add(retreivedObj!!)
}
}
}
}
}
with get method :
fun retrievePairsFromFirebase() {
database.collection("Pairs").document(currentUserEmail!!).collection("Pair").get()
.addOnSuccessListener { querySnapshot ->
if (querySnapshot.documents.isNotEmpty()) {
querySnapshot.documents.forEach {
val newPairObj = it.toObject(PairListModel::class.java)
pairState.add(newPairObj!!)
}
} else {
println("veriler indirilemedi")
}
}
}
kotlin's logger looks like:
open class KLogging : KLoggable {
override val logger: KLogger = logger()
}
suppose the following code is inside catch (err: Exception){...} what is the difference between
logger.error { "Some error $err" }
and
logger.error(err) { "Some error $err" }
?
I am using Json.decodeFromString<User>("json string") (https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serializers.md)
model is like
data class User(val id: String, val name: String, val assets: List<Asset>)
data class Asset(val id: String, val sku: String, val name: String)
but input json is like
{
"data": {
"id": "userId",
"name": "userName",
"body": {
"assets": [
{
"data": {
"id": "assetId",
"sku": "assetSku",
"name": "assetName"
}
}
]
}
}
}
How can I parse json with serializer? Seems not able to parse with delegate and surrogate serializers easily.
Your POJO seems to be wrong , every field needs to have name corresponding to json value , or use GSON's SerializedName annotation and Parse sing Gson.
Your User POJO should look something like this,
data class User (
#SerializedName("data") var data : UserData
)
data class UserData(
#SerializedName("id") var id : String,
#SerializedName("name") var name : String,
#SerializedName("body") var body : Body
)
data class Body (
#SerializedName("assets") var assets : List<Assets>
)
data class Assets (
#SerializedName("data") var data : AssetsData
)
data class AssetsData(
#SerializedName("id") var id : String,
#SerializedName("sku") var sku : String,
#SerializedName("name") var name : String
)
for serializing and deserializing
dependencies {
implementation 'com.google.code.gson:gson:2.8.9'
}
val gson = Gson()
val jsonValue = gson.toJson(User)
val jsonToUser = gson.fromJson(jsonValue ,User::class.java)
Read about https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/json.md#under-the-hood-experimental
Tried something like this:
#Serializable(with = AssetSerializer::class)
data class Asset(val id: String, val sku: String, val name: String)
#Serializable(with = UserSerializer::class)
data class User(val id: String, val name: String, val assets: List<Asset>)
object AssetSerializer: KSerializer<Asset> {
override val descriptor: SerialDescriptor =
buildClassSerialDescriptor("Asset") {
element("data", buildClassSerialDescriptor("data") {
element("id", String.serializer().descriptor)
element("sku", String.serializer().descriptor)
element("name", String.serializer().descriptor)
})
}
override fun serialize(encoder: Encoder, value: Asset) {
require(encoder is JsonEncoder)
encoder.encodeJsonElement(buildJsonObject {
put("data", buildJsonObject {
put("id", value.id)
put("sku", value.sku)
put("name", value.name)
})
})
}
override fun deserialize(decoder: Decoder): Asset {
require(decoder is JsonDecoder)
val root = decoder.decodeJsonElement()
val element = root.jsonObject["data"]!!
return Asset(
id = element.jsonObject["id"]!!.jsonPrimitive.content,
sku = element.jsonObject["sku"]!!.jsonPrimitive.content,
name = element.jsonObject["name"]!!.jsonPrimitive.content,
)
}
}
object UserSerializer: KSerializer<User> {
override val descriptor: SerialDescriptor =
buildClassSerialDescriptor("User") {
element("data", buildClassSerialDescriptor("data") {
element("id", String.serializer().descriptor)
element("name", String.serializer().descriptor)
element("body", buildClassSerialDescriptor("body") {
element("assets", ListSerializer(Asset.serializer()).descriptor)
})
})
}
override fun serialize(encoder: Encoder, value: User) {
require(encoder is JsonEncoder)
encoder.encodeJsonElement(buildJsonObject {
put("data", buildJsonObject {
put("id", value.id)
put("name", value.name)
put("body", buildJsonObject {
put("assets", JsonArray(value.assets.map { asset ->
encoder.json.encodeToJsonElement(asset)
}))
})
})
})
}
override fun deserialize(decoder: Decoder): User {
require(decoder is JsonDecoder)
val root = decoder.decodeJsonElement()
val element = root.jsonObject["data"]!!
val assets = element
.jsonObject["body"]!!
.jsonObject["assets"]!!
.jsonArray
.map { asset ->
decoder.json.decodeFromJsonElement(asset)
}
return Asset(
id = element.jsonObject["id"]!!.jsonPrimitive.content,
name = element.jsonObject["name"]!!.jsonPrimitive.content,
assets = assets,
)
}
}
I'm new to Ktor, I come from a Retrofit background, and I want to map this json:
{
"key1": "value1",
"key2": "value2",
...
}
into (actually I don't need to map the json itself only the deserialized version):
[
{"key1": "value1"},
{"key2": "value2"},
...
]
#Serializable
data class MyObject(
val member1: String,
val member2: String
)
The samples I've seen in official docs didn't help much, so I was trying something like:
#InternalSerializationApi
object CustomDeserializer : DeserializationStrategy<List<MyObject>> {
#ExperimentalSerializationApi
override val descriptor = buildSerialDescriptor("MyObject", PolymorphicKind.OPEN){
element("key", String.serializer().descriptor)
element("value", String.serializer().descriptor)
}
#ExperimentalSerializationApi
override fun deserialize(decoder: Decoder): List<MyObject> = decoder.decodeStructure(descriptor) {
val result = ArrayList<MyObject>()
loop# while (true) {
val index = decodeElementIndex(descriptor)
if (index == DECODE_DONE) {
break#loop
} else if (index > 1) {
throw SerializationException("Unexpected index $index")
} else {
result.add(MyObject(decodeStringElement(descriptor, index = 0), decodeStringElement(descriptor, index = 1)))
}
}
return result
}
}
Questions:
Am I in the right path, or there are better ways to achieve it?
How do I add this to my client? (it could be only for a specific request)
ps: this is how I would do it with Gson (ignore the fact this is in Java):
public class MyObjectConverterFactory implements JsonDeserializer<List<MyObject>> {
#Override
public List<MyObject> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
List<MyObject> res = new ArrayList<>();
if (json != null && json.getAsJsonObject() != null) {
JsonObject object = json.getAsJsonObject();
Set<String> keys = object.keySet();
for (String key : keys) {
res.add(new MyObject(key, object.get(key).getAsString()));
}
}
return res;
}
}
As far as I get it from GSON implementation, you need to deserialize from JSON
{"key1":"value1","key2":"value2", ...}
into
listOf(MyObject(member1="key1", member2="value1"), MyObject(member1="key2", member2="value2"), ...)
It's possible with kotlinx.serialization too:
object MyObjectListSerializer : JsonTransformingSerializer<List<MyObject>>(ListSerializer(MyObject.serializer())) {
override fun transformDeserialize(element: JsonElement) =
JsonArray((element as JsonObject).entries.map { (k, v) ->
buildJsonObject {
put("member1", k)
put("member2", v)
}
})
}
Usage (plain kotlinx.serialization):
val result = Json.decodeFromString(MyObjectListSerializer, "{\"key1\":\"value1\",\"key2\":\"value2\"}")
Usage (with Ktor client):
val client = HttpClient {
install(JsonFeature) {
serializer = KotlinxSerializer(Json {
serializersModule = SerializersModule { contextual(MyObjectListSerializer) }
})
}
}
val result = client.get<List<MyObject>>("http://localhost:8000/myObj")
I am trying to convert a string to JSONArray but I am having issues.
This is my test:
class MainActivityTest {
#Test
fun checkParse(){
val loader = ClassLoader.getSystemClassLoader()
val json: String = Files.lines(
get(
loader.getResource("data.json").toURI()
)
)
.parallel()
.collect(Collectors.joining())
val main = MainActivity()
val dataParse2 = Gson().fromJson(json, JSONArray::class.java)
val gson = GsonBuilder().create()
val parse2 = gson.fromJson(json, Array<QuoteModel>::class.java).toList()
val parse1 = main.parseResponse(dataParse2)
assertEquals(parse1,parse2)
}
}
This is the function I am testing in my MainActivity:
fun parseResponse(response: JSONArray): List<QuoteModel> {
val fileData = response.toString()
val gson = GsonBuilder().create()
return gson.fromJson(fileData, Array<QuoteModel>::class.java).toList()
}
And this is my data.json file:
[
{
"text": "Genius is one percent inspiration and ninety-nine percent perspiration.",
"author": "Thomas Edison"
},
{
"text": "You can observe a lot just by watching.",
"author": "Yogi Berra"
},
{
"text": "A house divided against itself cannot stand.",
"author": "Abraham Lincoln"
}
]
the issue comes in this line from my test:
val dataParse2 = Gson().fromJson(json, JSONArray::class.java)
Any ideas?
First Update
This is the function where I call the parseFunction in MainActivity:
private fun jsonArrayRequest(url: String): JsonArrayRequest {
return JsonArrayRequest(Request.Method.GET, url, null,
{ response ->
val quotesArray = parseResponse(response)
displayQuote(chooseQuote(quotesArray))
},
{ error ->
TODO("Handle error missing")
}
)
}
private fun jsonArrayRequest(url: String): JsonArrayRequest {
return JsonArrayRequest(Request.Method.GET, url, null,
{ response ->
val responseArray = JSONArray(response)
val quotesArray = parseResponse(responseArray)
displayQuote(chooseQuote(quotesArray))
},
{ error ->
TODO("Handle error missing")
}
)
fun parseResponse(response: JSONArray): List<QuoteModel> {
return Gson().fromJson(response.toString(), Array<QuoteModel>::class.java).toList()