Je travaille sur un projet Android nécessitant un JSONObject pour le corps de ma demande POST. Après avoir mis les clés et les valeurs du JSON, j'ai obtenu la ligne suivante:
{
"xxxx":"zzzzzzz",
"yyyy":"uuuuuuu"
}
Mais le serveur a ce qui suit:
{
"name_value_pairs": {
"xxxx":"zzzzzzz",
"yyyy":"uuuuuuu"
}
}
J'ai déjà essayé un JSONStringer mais ce n'était pas très utile car le Content-Type
de la requête est application/json
.
METTRE À JOUR
Je n'essaye pas de construire un JSONObject parce que c'est déjà fait en utilisant la ligne de code suivante (identique à @osayilgan):
JSONObject jsonRequest = new JSONObject();
jsonRequest.put("xxxx", "zzzzzzz");
jsonRequest.put("yyyy", "uuuuuuu");
Voici pas le problème. L'interface décrite ci-dessous est utilisée pour communiquer avec le serveur.
public interface MyService {
@Headers({"Content-type: application/json",
"Accept: */*"})
@POST("/test")
void testFunction(@Body JSONObject jsonObject, Callback<Response> callback);
}
Le serveur a reçu la demande avec le deuxième JSON en tant que Body, ce qui est décevant. Je remarque que la clé name_value_pairs
est automatiquement ajoutée à l'objet.
Est-ce que quelqu'un sait comment puis-je résoudre ce problème?
Issue :
Retrofit utilise par défaut GSON pour convertir les corps HTTP en JSON et à partir de ceux-ci. L'objet spécifié avec l'annotation @Body sera passé à GSON pour la sérialisation, qui convertira l'objet Java en représentation JSON. Cette représentation JSON sera le corps de la requête HTTP.
JSONObject stocke tout le mappage clé-valeur dans une variable membre nommée nameValuePairs
. Voici un extrait de la mise en oeuvre de JSONObject:
public class JSONObject {
...
private final Map<String, Object> nameValuePairs;
...
}
Lorsque vous transmettez JSONObject à l'annotation @Body, ce JSONObject est mis à jour. Le corps de la requête HTTP contient donc: {"nameValuePairs": "Objet JSON réel"}.
Solution:
Passez l'objet Java réel à l'annotation @Body, et non à JSONObject correspondant. GSON se chargera de la convertir en représentation JSON.
Par exemple.
class HTTPRequestBody {
String key1 = "value1";
String key2 = "value2";
...
}
// GSON will serialize it as {"key1": "value1", "key2": "value2"},
// which will be become HTTP request body.
public interface MyService {
@Headers({"Content-type: application/json",
"Accept: */*"})
@POST("/test")
void postJson(@Body HTTPRequestBody body, Callback<Response> callback);
}
// Usage
MyService myService = restAdapter.create(MyService.class);
myService.postJson(new HTTPRequestBody(), callback);
Solution alternative:
Si vous souhaitez toujours envoyer du JSON brut en tant que corps de requête HTTP, suivez la solution indiquée par l'auteur de Retrofit ici .
L'une des solutions suggérées consiste à utiliser TypedInput :
public interface MyService {
@POST("/test")
void postRawJson(@Body TypedInput body, Callback<Response> callback);
}
String json = jsonRequest.toString();
TypedInput in = new TypedByteArray("application/json", json.getBytes("UTF-8"));
myService.postRawJson(in, callback);
Merci à 13KZ, m'a orienté dans la bonne direction, et pour préciser, voici ce que je dois maintenant pour résoudre ce problème.
Définitions
private JsonObject gsonResultTwoWeek;
private JsonObject gsonResultDay;
private JsonObject gsonResult;
Initialiser
gsonResult = new JsonObject();
gsonResultDay = new JsonObject();
gsonResultTwoWeek = new JsonObject();
Utilisation
gsonResultDay.addProperty(Epoch, value);
où data est une chaîne et value est un int dans mon cas et se trouve dans une boucle for pour ajouter plusieurs valeurs
Et puis pour tout arranger
gsonResult.addProperty("accounts", 2);
gsonResult.add("todaydata", gsonResultDay);
gsonResult.add("2weekdata", gsonResultTwoWeek);
Enfin mon interface
public interface ApiInterface {
@POST("/groupdata")
void postGroupData(@Body JsonObject body,Callback<StatusResponse> cb);
}
Ce qui frappe mon serveur est-ce
{"accounts":2,"todaydata":{"1423814400":89,"1423816200":150,"1423818000":441},"2weekdata":{"1423699200":4869,"1423785600":1011}}
Ma solution est basée sur 13KZ
public class MyRequest {
@SerializedName(Constants.ID)
private String myID;
@SerializedName(Constants.PARAM_ANSWERS)
private JsonObject answers;
public MyRequest(String id, Hasmap<String, String> answers) {
this.myID = id;
this.answers = new JsonObject();
for (String s: answers.keySet()) {
this.answers.addProperty(s, answers.get(s));
}
}
}
Il semble que vous tentiez de transmettre la valeur JSONObject
réelle plutôt que la représentation de chaîne de texte JSON de l'objet. Un examen de la spécification de la classe JSONObject
montre que vous devez utiliser la méthode .toString()
pour obtenir la représentation JSON de la structure de données conservée par la variable JSONObject
. Ainsi, vous devriez pouvoir changer:
public interface MyService {
@Headers({"Content-type: application/json",
"Accept: */*"})
@POST("/test")
void testFunction(@Body JSONObject jsonObject, Callback<Response> callback);
}
à:
public interface MyService {
@Headers({"Content-type: application/json",
"Accept: */*"})
@POST("/test")
void testFunction(@Body String jsonObject.toString(), Callback<Response> callback);
}
Le seul changement étant JSONObject jsonObject
à String jsonObject.toString()
.
Alternativement, vous pouvez le forcer brutalement en prenant simplement la chaîne que vous avez du JSON et en remplaçant '"name_value_pairs": {'
par ''
et le dernier '}'
dans la chaîne par ''
. JSON est juste une chaîne de texte. Autre que ce soit inélégant, il n'y a aucune raison pour que vous ne puissiez pas manipuler le texte. Ces deux remplacements donneront un objet texte JSON valide. L'indentation des espaces ne sera pas correcte pour un humain, mais une machine qui analyse la chaîne JSON ne se soucie pas de savoir si les espaces sont corrects.