Почему я постоянно получаю null вместо значения строки в JSON?

Я пробовал две библиотеки для работы с JSON: GSON и FastJson.

JSON (кусок):


{
...
"Layout1BottomContent": ["Selection'@string/Selection'", "Folder'@string/New'",  "*NewDir'@string/NewDir'", "*NewFile'@string/NewFile'", "Folder'Open'", "*OpenAssoc'@string/OpenAssoc'", "*OpenWith'@string/OpenWith'", "*OpenAs'@string/OpenAs'", "Delete'@string/Delete'", "Copy'@string/Copy'", "Compress'@string/Compress'", "Extract'@string/Extract'", "Folder'Menu'"],
"Layout1BottomAppearance": ["60", "Fit", "Center", "Rounded", "Icon", "Expandable"],
"Layout1Top": "NormBarPinned",
...
}

Пытался парсить через FastJson:

public class MainPageBasicLayout extends AppCompatActivity {

    int Layout1BottomLvl1Num = 0;
    String[] Layout1BottomLvl1Features = new String[9];
    String[] Layout1BottomLvl1Items = new String[9];

    //JSON Fields
    @JSONField
    String Layout1Bottom = null;
    @JSONField
    List<String> Layout1BottomContent;
    @JSONField
    List<String> Layout1BottomAppearance;
    @JSONField
    String ExitBehavior;
    @JSONField
    int Layout1BottomNum = 0;

    public MainPageBasicLayout() {
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_page);


        //Get JSON file content

        String JSON = null;
        try {
            JSON = new CfgMgr().GetJsonFileContent(this);
        } catch (IOException e) {
            e.printStackTrace();
        }

        MainPageBasicLayout Obj = com.alibaba.fastjson.JSON.parseObject(JSON, MainPageBasicLayout.class);

}

Потом пытался через GSON:

public class MainPageBasicLayout extends AppCompatActivity {

    int Layout1BottomLvl1Num = 0;
    String[] Layout1BottomLvl1Features = new String[9];
    String[] Layout1BottomLvl1Items = new String[9];

    //JSON Fields
    @Expose
    String Layout1Bottom = null;
    @Expose
    List<String> Layout1BottomContent;
    @Expose
    List<String> Layout1BottomAppearance;
    @Expose
    String ExitBehavior;
    @Expose
    int Layout1BottomNum = 0;

    public MainPageBasicLayout() {
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_page);


        //Get JSON file content

        String JSON = null;
        try {
            JSON = new CfgMgr().GetJsonFileContent(this);
        } catch (IOException e) {
            e.printStackTrace();
        }

           GsonBuilder builder = new GsonBuilder();
        Gson gson = builder.excludeFieldsWithoutExposeAnnotation().create();
        MainPageBasicLayout Obj = gson.fromJson(JSON, MainPageBasicLayout.class);
}

А затем я пытаюсь выполнить Integer.parseInt(Layout1BottomAppearance.get(0)), но получаю:

NullPointerException: Attempt to invoke interface method 'java.lang.Object java.util.List.get(int)' on a null object reference

P.S. Код GetJsonFileContent:

public String GetJsonFileContent(Context Context) throws IOException {

        File Cfg = new File("/data/data/mate.files/", "Cfg.json");

        String PreparedData = "";
        int CfgLength = CfgStr.getBytes().length;
        char[] Char;
        Char = new char[CfgLength];
        InputStreamReader InputRdr = new InputStreamReader(Context.openFileInput("Cfg.json"));
        InputRdr.read(Char, 0, CfgLength);

        int Counter = 0;
        //Convert char array to String
        for (Counter = 0; Counter != CfgLength; Counter++) {
            PreparedData = PreparedData + Char[Counter];
        }
        InputRdr.close();

        return PreparedData;
    }

Ответы (1 шт):

Автор решения: Михаил Ребров

Объяснение ошибки

Я полагаю, что все из-за того, что Вы извлекаете данные из JSON'да и кладёте их в один объект, а потом пытаетесь получить их из другого.

На примере:

MainPageBasicLayout Obj = com.alibaba.fastjson.JSON.parseObject(JSON, MainPageBasicLayout.class);

Вы извлекаете данные из JSON и сохраняете их в Obj

После чего вы вызываете следующий код:

Integer.parseInt(Layout1BottomAppearance.get(0))

Здесь не указано, где именно он расположен, но насколько могу себе представить он расположен внутри MainPageBasicLayout, а если это так, то в двух вышеприведенных строках вы обращаетесь к разным объектам.

Отсюда и следует NullPointerException:
Вы сохранили данные в Obj, а потом пытаетесь получить их же в this.

Вы должны были обращаться:

Obj.Layout1BottomAppearance.get(0)

а вместо этого обратились

this.Layout1BottomAppearance.get(0)

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

Рекомендации

Я бы предостерег Вас от попыток вручную создавать и манипулировать объектами Activity - оставьте это на откуп Android'у

Отсюда следует что не стоит пытаться из JSON'а создать Activity.

Если хотите что-то извлечь из JSON и применить к Activity:

  1. Создайте отдельный класс настроек Activity, например ActivitySettings
  2. Извлеките данные из JSON в объект данного типа.
  3. Примените настройки используя полученный объект

Пример

Создаем класс описывающий модель хранимых в JSON данных

public class ActivitySettings {
    @Expose
    String Layout1Bottom = null;
    @Expose
    List<String> Layout1BottomContent;
    @Expose
    List<String> Layout1BottomAppearance;
    @Expose
    String ExitBehavior;
    @Expose
    int Layout1BottomNum = 0;
    // ...
}

Ну и потом извлекаем:

GsonBuilder builder = new GsonBuilder();
Gson gson = builder.excludeFieldsWithoutExposeAnnotation().create();
ActivitySettings settings = gson.fromJson(JSON, ActivitySettings.class);

результат в дебаггере

введите сюда описание изображения

как видим в settings прекрасно хранятся значения из Json.

И потом вы можете их брать и использовать как вам нужно.

Замечание

Вы часто используете имена

  • переменных (Obj),
  • полей (ExitBehavior),
  • методов (GetJsonFileContent())

начинающихся с заглавной буквы

В Java так делать нельзя!

В Java есть конвенции, которые четко определяют, что названия классов всегда должны начинаться с заглавной, а переменных и методов с прописной.

Если боитесь за различие название полей в классе и JSON'е - используйте аннотацию @SerializedName с указанием названия поля в JSON

public class ActivitySettings {
    @Expose
    @SerializedName("Layout1Bottom")
    String layout1Bottom = null;
    @Expose
    @SerializedName("Layout1BottomContent")
    List<String> layout1BottomContent;
    @Expose
    @SerializedName("Layout1BottomAppearance")
    List<String> layout1BottomAppearance;
    @Expose
    @SerializedName("ExitBehavior")
    String exitBehavior;
    @Expose
    @SerializedName("Layout1BottomNum")
    int layout1BottomNum = 0;
    // ...
}
→ Ссылка