adlnet / jxapi

Apache License 2.0
37 stars 24 forks source link

Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 - When posting new Statement #32

Open venkatapathy opened 7 years ago

venkatapathy commented 7 years ago

Guys,

I am trying to use jxapi with OpenLrs- which is an open source LRS written in Java. So when I try to Post a single statement (or multiple statements for that matter), it returns Json response as Jsonarray. For eg: For a post statement below:

{
  "actor": {
    "name": "Sally Glider",
    "mbox": "mailto:sally@example.com"
  },
  "verb": {
    "id": "http://adlnet.gov/expapi/verbs/experienced",
    "display": { "en-US": "experienced" }
  },
  "object": {
    "id": "http://example.com/activities/solo-hang-gliding",
    "definition": {
      "name": { "en-US": "Solo Hang Gliding" }
    }
  }
}

OpenLrs' response is:

[
  "c250f7a5-859b-4080-a8cb-0972fa76b25d"
]

Now this throws an error: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2

in the class-StatementClient in the function:

public String postStatement(Statement statement)

at line: JsonArray jsonResult = gson.fromJson(result, JsonArray.class);

I even tried to convert the response to Jsonarray at the source- Openlrs before returning, but it still throws the same error.

Could someone tell me what's the expected response? In the specification, there is no hint given except that it says the POST should return an array of id, which as I see it, the Openlrs does follow suit? Could anyone please help me? Thanks

rneatrour commented 7 years ago

The jxapi postStatement method will return a single ID, and it's a string.

String publishedId = statementClient.postStatement(statement);

The postStatements method will return an ID for each statement in an ArrayList.

ArrayList<String> publishedIds = statementClient.postStatements(statements);
venkatapathy commented 7 years ago

Hi, Thanks for the reply. I still have a doubt on this. I agree that:

String publishedId = statementClient.postStatement(statement);

returns a single ID which is a string. But, in the code StatementClient.postStatement(statement), you still parse an array of IDs and return the first ID:

JsonArray jsonResult = gson.fromJson(result, JsonArray.class);
return jsonResult.get(0).getAsString();

So basically both statementClient.postStatement(statement) and statementClient.postStatements(statements) expect results with same JSON format from LRS. My question is what is this format should be, because:


[
  "c250f7a5-859b-4080-a8cb-0972fa76b25d"
]

for statementClient.postStatement(statement), throws an exception. For example, could you tell me what should be a return JSON object from the LRS for a statement:

{
  "actor": {
    "name": "Sally Glider",
    "mbox": "mailto:sally@example.com"
  },
  "verb": {
    "id": "http://adlnet.gov/expapi/verbs/experienced",
    "display": { "en-US": "experienced" }
  },
  "object": {
    "id": "http://example.com/activities/solo-hang-gliding",
    "definition": {
      "name": { "en-US": "Solo Hang Gliding" }
    }
  }
}

Based on that I will change the LRS side response code. Note that the statement is successfully stored in the LRS and the Statement ID is returned. The problem is only in the parsing of the JSON response at line: JsonArray jsonResult = gson.fromJson(result, JsonArray.class);

Thanks

ljwolford commented 7 years ago

Whenever one or more statements are POSTed, the LRS must return an array of IDs, like you described. So if a single statement is posted, the LRS should return ["c250f7a5-859b-4080-a8cb-0972fa76b25d"]. jXAPI then just parses that result and returns the single ID as a string for usability. Have you tried POSTing to a different LRS to see if the error still occurs?

venkatapathy commented 7 years ago

Hi,

I tried to POSTed a statement to

https://lrs.adlnet.gov/xAPI/

LRS successfully stored the statement and returned the ID. And the jxApi still threw an JsonSyntaxException as mentioned above.

So guess its a bug?

You can find the following statement at http://adlnet.github.io/xapi-statement-viewer/:

{
  "verb": {
    "id": "http://adlnet.gov/expapi/verbs/launched",
    "display": {
      "en-US": "launched"
    }
  },
  "version": "1.0.0",
  "timestamp": "2017-06-05T12:53:27.836827+00:00",
  "object": {
    "id": "https://www.youtube.com/watch?v=tlBbt5niQto",
    "objectType": "Activity"
  },
  "actor": {
    "mbox": "mailto:venkat.s.iyer@gmail.com",
    "objectType": "Agent"
  },
  "stored": "2017-06-05T12:53:27.836827+00:00",
  "authority": {
    "mbox": "mailto:techteam+xapi-tools@adlnet.gov",
    "name": "xapi-tools",
    "objectType": "Agent"
  },
  "id": "a14600cc-4e39-483b-b040-0aa0ae94f04f"
}
rneatrour commented 7 years ago

This test posts and returns an ID with no exceptions thrown.

StatementClient client = new StatementClient(lrs_uri, username, password);

Statement st = new Statement(new Agent("test", mbox), 
                new Verb("http://adlnet.gov/expapi/verbs/launched"), 
                new Activity("https://www.youtube.com/watch?v=tlBbt5niQto"));

String publishedId = client.postStatement(st);

It returns d03a76ac-c3e6-4e3d-8354-ce7bc6898489

The statement stored:

{
  "verb": {
    "id": "http://adlnet.gov/expapi/verbs/launched"
  },
  "version": "1.0.0",
  "timestamp": "2017-06-05T13:18:12.401968+00:00",
  "object": {
    "id": "https://www.youtube.com/watch?v=tlBbt5niQto",
    "objectType": "Activity"
  },
  "actor": {
    "mbox": "mailto:jxapi@example.com",
    "name": "test",
    "objectType": "Agent"
  },
  "stored": "2017-06-05T13:18:12.401968+00:00",
  "authority": {
    "mbox": "mailto:test@example.com",
    "objectType": "Agent"
  },
  "id": "d03a76ac-c3e6-4e3d-8354-ce7bc6898489"
}

Is there a public link to your LRS for me to test against?

venkatapathy commented 7 years ago

Originally I had my own local server from compiled from:

https://github.com/Apereo-Learning-Analytics-Initiative/OpenLRS

But I also tested with the ADL's LRS. The following code also throws an exception:

Statement statement = new Statement(new Agent("test", "mailto:jxapi@example.com"), new                Verb("http://adlnet.gov/expapi/verbs/launched"),
                    new Activity("https://www.youtube.com/watch?v=tlBbt5niQto"));

StatementClient client=new StatementClient("https://lrs.adlnet.gov/xapi/", "xapi-tools",
                    "xapi-tools");

            // send the statement, if successful store the uuid for future
            // references
            try {
                String publishedId = client.postStatement(statement);

        } catch (JsonSyntaxException e) {
            // ignore due to a bug
            System.out.println("Exception while reading the Id!!");

        } 
ruizrube commented 4 years ago

I got the same exception when sending a xAPI statement to a Learning Locker instance. Anyway, the statement is properly saved in the store.