简体   繁体   中英

Valid Json throws “Expected BEGIN_OBJECT but was STRING at line 1 column 4”

I know lot of people asked similars questions but, hell I'm stuck and I don't understand why. That's weird because the JSON is valid on jsonlint :

{
    "Name": "Geography",
    "Questions": [{
        "_question": "Where is Max?",
        "_answers": ["France", "USA", "Spain", "Tunisia"],
        "_correctOne": 2,
        "Asked": false,
        "ID": 0
    }, {
        "_question": "Where is the Eiffel Tower?",
        "_answers": ["Marseilles", "Le Mans", "Paris", "Lyon"],
        "_correctOne": 3,
        "Asked": false,
        "ID": 1
    }, {
        "_question": "Where is Barcelona?",
        "_answers": ["Italy", "Germany", "Portugual", "Spain"],
        "_correctOne": 4,
        "Asked": false,
        "ID": 2
    }, {
        "_question": "Where is Malibu point?",
        "_answers": ["San Francisco", "San Diego", "Los Angeles", "It\u0027s just in a movie"],
        "_correctOne": 3,
        "Asked": false,
        "ID": 3
    }, {
        "_question": "Where takes place the famous 24h of Le Mans?",
        "_answers": ["France", "Belgium", "Canada", "Martinique"],
        "_correctOne": 1,
        "Asked": false,
        "ID": 4
    }, {
        "_question": "Which one of the following countries is the biggest one?",
        "_answers": ["Mexico", "USA", "Russia", "India"],
        "_correctOne": 3,
        "Asked": false,
        "ID": 5
    }, {
        "_question": "Where can you find a Camel?",
        "_answers": ["Siberia", "Antartic", "Artic", "Sahara"],
        "_correctOne": 4,
        "Asked": false,
        "ID": 6
    }, {
        "_question": "Where can\u0027t you find the statue of the liberty?",
        "_answers": ["New York", "Paris", "Las Vegas", "Strasbourg"],
        "_correctOne": 2,
        "Asked": false,
        "ID": 7
    }, {
        "_question": "What did Christophe Colomb has discovered?",
        "_answers": ["Europe", "America", "Africa", "Asia"],
        "_correctOne": 2,
        "Asked": false,
        "ID": 8
    }, {
        "_question": "Where can\u0027t you practice sky?",
        "_answers": ["Maroco", "Canada", "Norway", "Dubaï"],
        "_correctOne": 1,
        "Asked": false,
        "ID": 9
    }, {
        "_question": "Which one of the following countries isn\u0027t a neighboor of the France?",
        "_answers": ["Germany", "Italy", "Spain", "Portugual"],
        "_correctOne": 4,
        "Asked": false,
        "ID": 10
    }]
}

So, it's just an ArrayList<Category> . Category is the following class:

public class Category {

    public String Name;
    public ArrayList<Question> Questions;

}

Also, the Question class below:

public class Question {

    private String _question;
    private String[] _answers;
    private int _correctOne;
    public boolean Asked;
    public int ID;

}

Everything seems alright to me, I checked again and again, still have this error. However, something seems weird, each ' is replaced by \' , but it doesn't seems to be the problem..

I'm parsing the Gson from the following function:

public static boolean ReadCategoryFileTxt(Category category) {

    try {

        File file = new File(category.Name + ".txt");
        Scanner sc = new Scanner(file);
        String JSONString = "";

        while (sc.hasNextLine()) 
            JSONString += sc.nextLine();

        Gson gson = new Gson();
        Category _category = gson.fromJson(JSONString, Category.class);

        category.Name = _category.Name;
        category.Questions = _category.Questions;

        //Debug.Println(gson.toJson(category, Category.class));

        sc.close();
    }
    catch (Exception e)
    {
        Debug.PrintException(e);
        return (false);
    }

    return (true);
}

Any idea for this "Expected BEGIN_OBJECT but was STRING at line 1 column 4"?

Thank in advance !

Looks the start of the JSON read from file is not open flower braces {

Point 1 - See if the file has any incorrect start characters

Point 2 - Set your text file encoding to UTF -8

Point 3 - Use String Builder instead of using + append assignment

Point 4 - If you have notepad++, you shall remove non-ascii characters using - Notepad++, How to remove all non ascii characters with regex?

public static boolean ReadCategoryFileTxt(Category category) {

    try {

        File file = new File(category.Name + ".txt");
        Scanner sc = new Scanner(file);
        StringBuilder JSONString = new StringBuilder;

        while (sc.hasNextLine()) 
            JSONString = JSONString.append(sc.nextLine());

        Gson gson = new Gson();
        Category _category = gson.fromJson(JSONString.toString().trim(), Category.class);

        category.Name = _category.Name;
        category.Questions = _category.Questions;

        //Debug.Println(gson.toJson(category, Category.class));

        sc.close();
    }
    catch (Exception e)
    {
        Debug.PrintException(e);
        return (false);
    }

    return (true);
}

I'd like to leave a few words based on what you clarified in the comments. To be honest, I could not reproduce the exact exception with ... line 1 column 4 having ... line 1 column 1 instead, regardless the default JVM file.encoding property , but you're faced with a classic file encoding issue.

  • Your JSON is really well-formed.
  • Java promotes some naming conventions so _question and Asked appearing in the JSON can be expressed as @SerializedName("_question") String question; and @SerializedName("Asked") boolean isAsked; respectively.
  • \' is an escaped character of ' . Characters can be unescaped if they are a part of the enclosing document encoding. The apostrophe fits ASCII just perfect, however it may be escaped in order not to break JSON documents syntactically, say, string literals in JSON strings.
  • The real problem was that your JSON file was not invalid characters per se, but an UTF-8 encoded file with an explicit Byte Order Mark that should be processed before parsing begins to make sure that file content encoding is detected and decoded fine (  literally stands for UTF-8 ). UTF-aware editors just do not show BOMs since the latter are not considered bad or illegal characters, but use them to deal with UTF-encoded files (file encoding names are usually shown in statusbars, etc). That's why copying/pasting worked for you: BOMs were not included to copies (they "live" in files only, and in clipboard metadata I guess). By default, Java classes do not make any assumptions on the incoming file encoding leaving the decision on it on your own or even on user's own. It is described here . Therefore Gson should not process it and Gson really does not do it. All Gson can only consume is JSON tokens streams (and that's perfect design), so you have either to detect the input encoding, or let your user specify it.
  • You don't need to accumulate an intermediate String to parse a JSON: this is just memory wasting especially for big JSON documents. Gson can work in streaming manner, so it accepts Reader instances in order not to accumulate intermediate JSON strings reading a given input stream token by token trying to consume as less memory as possible. Also note that reading line by line is cheaper with BufferedReader rather than Scanner , however it's still discouraged for you case.
  • If you're using Java 7 or later, use try-with-resources to make sure your I/O resources are not leaked (otherwise use finally to make sure there are no resource leaks). Also it's worth noting that instantiating a Gson instance may be considered a little expensive operation, and since Gson instances are thread-safe and immutable, they can be instantiated once per application and shared globally (not necessarily a public static final Gson ... , of course, but something encapsulated elsewhere in a good design solution).
try( final Reader reader = new InputStreamReader(new FileInputStream(new File(category.Name + ".txt")), StandardCharsets.UTF_8)) {
    Category _category = gson.fromJson(reader, Category.class);

    category.Name = _category.Name;
    category.Questions = _category.Questions;

    //Debug.Println(gson.toJson(category, Category.class));
} catch ( Exception e ) {
    Debug.PrintException(e);
    return (false);
}

return (true);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM