Как сериализовать строки и подмассив (объект?) Из строк gson - PullRequest
0 голосов
/ 06 апреля 2020

Начинающий!

У меня есть приложение для викторины полный код на Github , который загружает List с четырьмя аргументами из json (данные ранее хранились в xml):

  1. вопрос
  2. изображение
  3. четыре возможных ответа, представленные в radioGroup (подсписок)
  4. правильный ответ
   [{
        "question": "Who is the 'Modern Love' rock star singer?",
        "imageUrl": "https://postimg.cc/2VL1Y1jd",
        "answerOptions": [{
            "1": "Jaimie Hendrix",
            "2": "David Bowie",
            "3": "Jim Morrison",
            "4": "Elvis Presley"
        }],
        "correctAnswer": "David Bowie"
    }]

Я получаю сообщение об ошибке

java .lang.IllegalStateException: ожидаемая строка, но была BEGIN_OBJECT в строке 1 столбца 118 путь $ [0] .answerOptions [0]

, и это потому, что я объявил все типы данных, запрошенные как строки, в то время как у меня есть массив смешанных типов (объект и массив):

@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
     if (response.isSuccessful()) {
          String string = response.body().string();
          Gson gson = new Gson();
          Type type = new TypeToken<List<Quiz>>(){}.getType();
          List<Quiz> list = gson.fromJson(string, type);

          // Save to database
          for (int i = 0; i < list.size(); i++) {
              Quiz quiz = list.get(i);
              quiz.save();
          }
...

Я мог бы реализовать решение здесь в классе моста:

class Quiz extends LitePalSupport {
    String question;
    String imageUrl;
    String [] answerOptions;
    String correctAnswer;

    Quiz(String question, String imageUrl, String [] answerOptions, String correctAnswer) {
        this.question = question;
        this.imageUrl = imageUrl;
        this.answerOptions = answerOptions;
        this.correctAnswer = correctAnswer;
    }
}

, но это означает, что я буду отправлять подкласс в держатель представления адаптера, который ожидает String []

...
quizHolder.createRadioButtons(quiz.answerOptions);
...
void createRadioButtons(String[] answerOptions) {
    if (radioGroup.getChildAt(0) != null)
        radioGroup.removeAllViews();
    for (String s : answerOptions) {
        radioGroup.addView(createRadioButtonAnswerAndSetOnClickListener(s));
    }
}
...

Есть ли способ получить подсписок из json без создания подкласса?


Редактировать: * 104 5 *

После рекомендованного изменения @ andy-turner я получаю сообщение об ошибке:

org.litepal.exceptions.LitePalSupportException: Попытка вызвать виртуальный метод 'java .lang. Класс [] java .lang.reflect.Constructor.getParameterTypes () 'для пустой ссылки на объект

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.celebrityquiz, PID: 6493
    org.litepal.exceptions.LitePalSupportException: Attempt to invoke virtual method 'java.lang.Class[] java.lang.reflect.Constructor.getParameterTypes()' on a null object reference
        at org.litepal.crud.DataHandler.query(DataHandler.java:154)
        at org.litepal.crud.QueryHandler.onFindAll(QueryHandler.java:123)
        at org.litepal.Operator.findAll(Operator.java:1117)
        at org.litepal.Operator.findAll(Operator.java:1082)
        at org.litepal.LitePal.findAll(LitePal.java:798)
        at com.example.celebrityquiz.MainActivity$1$2.run(MainActivity.java:115)
        at android.os.Handler.handleCallback(Handler.java:751)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6077)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)
...

, вероятно, вызывается, когда я пытаюсь получить данные из базы данных:

List<Quiz> list = LitePal.findAll(Quiz.class);

И столбец answerOptions также не отображается

enter image description here

Ответы [ 2 ]

2 голосов
/ 06 апреля 2020
Ожидается, что

answerOptions будет String[], но вы указали его как Object[] (из-за {}):

    "answerOptions": [{
        ...
    }],

Сделайте его массивом строк:

    "answerOptions": [
        "Jaimie Hendrix",
        "David Bowie",
        "Jim Morrison",
        "Elvis Presley"
    ],

PS - "Jimi" , а не "Jaim ie".

1 голос
/ 06 апреля 2020

my propo

-> изменить Json заменить список (объекты или карту) на строки списка

package pl.jac.mija.gson;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;

import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.List;

import static org.junit.Assert.assertEquals;

public class QuizTestChangeJson {
  @Test
  public void changeJson() {
    //given
    String json = getNewJsonOneProposeOptions();
    Type type = new TypeToken<List<Quiz>>() {
    }.getType();
    //when
    List<Quiz> list = new Gson().fromJson(json, type);
    //then
    assertEquals(1, list.size());
    String correctAnswer = list.get(0).correctAnswer;
    assertEquals(correctAnswer, list.get(0).answerOptions[1]);
    assertEquals(1, Arrays.asList(list.get(0).answerOptions).indexOf(correctAnswer)); // key is string
  }

  @NotNull
  private String getNewJsonOneProposeOptions() {
    return "   [{\n" +
            "        \"question\": \"Who is the 'Modern Love' rock star singer?\",\n" +
            "        \"imageUrl\": \"https://postimg.cc/2VL1Y1jd\",\n" +
            "        \"answerOptions\": [\n" +
            "             \"Jaimie Hendrix\",\n" +
            "             \"David Bowie\",\n" +
            "             \"Jim Morrison\",\n" +
            "             \"Elvis Presley\"\n" +
            "        ],\n" +
            "        \"correctAnswer\": \"David Bowie\"\n" +
            "    }]";
  }
}

class Quiz {
  String question;
  String imageUrl;
  String[] answerOptions;
  String correctAnswer;
}

изменить викторину модели на Json

первая версия с ключом String -> QuizV2_String

вторая версия с ключом Long -> QuizV2_Long

Я добавил тест, чтобы вытащить ключ правильного ответа

 package pl.jac.mija.gson;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;

import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

import static org.junit.Assert.assertEquals;

public class QuizTestChangeModel {
  @Test
  public void changeModelQuizKeyString() {
    //given
    String json = getJsonOriginal();
    Type type = new TypeToken<List<QuizV2_String>>() {
    }.getType();
    //when
    List<QuizV2_String> list = new Gson().fromJson(json, type);
    //then
    assertEquals(1, list.size());
    assertEquals("David Bowie", list.get(0).answerOptions.get(0).get("2")); // key is string
  }

  @Test
  public void changeModelQuizKeyLong() {
    //given
    String json = getJsonOriginal();
    Type type = new TypeToken<List<QuizV2_Long>>() {
    }.getType();
    //when
    List<QuizV2_Long> list = new Gson().fromJson(json, type);
    //then
    assertEquals(1, list.size());
    assertEquals("David Bowie", list.get(0).answerOptions.get(0).get(2L)); // key is string
  }

  @Test
  public void changeModelQuizFindAnswer() {
    //given
    String json = getJsonOriginal();
    Type type = new TypeToken<List<QuizV2_String>>() {
    }.getType();
    //when
    List<QuizV2_String> list = new Gson().fromJson(json, type);
    //then
    String correctAnswer = list.get(0).correctAnswer;
    String key = list.get(0).answerOptions.get(0).entrySet().stream().filter(x -> correctAnswer.equals(x.getValue())).map(Map.Entry::getKey).findFirst().orElse(null);
    assertEquals("2", key);
    assertEquals("David Bowie", list.get(0).answerOptions.get(0).get(key));
  }

  @NotNull
  private String getJsonOriginal() {
    return "   [{\n" +
            "        \"question\": \"Who is the 'Modern Love' rock star singer?\",\n" +
            "        \"imageUrl\": \"https://postimg.cc/2VL1Y1jd\",\n" +
            "        \"answerOptions\": [{\n" +
            "            \"1\": \"Jaimie Hendrix\",\n" +
            "            \"2\": \"David Bowie\",\n" +
            "            \"3\": \"Jim Morrison\",\n" +
            "            \"4\": \"Elvis Presley\"\n" +
            "        }],\n" +
            "        \"correctAnswer\": \"David Bowie\"\n" +
            "    }]";
  }
}


class QuizV2_String {
  String question;
  String imageUrl;
  List<Map<String, String>> answerOptions;
  String correctAnswer;
}

class QuizV2_Long {
  String question;
  String imageUrl;
  List<Map<Long, String>> answerOptions;
  String correctAnswer;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...