简体   繁体   中英

Php Json Associative Array To Java Map

My problem is, PHP encodes arrays differently, based on if they are consecutive & begin with a zero index, or not. Example:

$arr = array(array(12), array(13));
===> [[12], [13]]

$arr = array("0" => array(12), "1" => array(13));
===> [[12], [13]]

$arr = array("0" => array(12), "2" => array(13));
===> {"0": [12], "2": [13]}

Why is the third one so radically different?

The first example produces a list of lists, the third example produces an object with lists. I need to convert all of these to Java 's Map<Integer, List<Double>> . That is the most generic datatype I could find in Java for these PHP objects. I am using Gson from Google. However, since the examples produces different types of objects, I cannot just read this into a map. I have to first check if it has indices and then adding one by one to a custom map. Please look at the line that says "THERE HAS TO BE A BETTER WAY TO DO THIS PART". This is my code:

import java.lang.StringBuilder;
import com.google.gson.*;
import com.google.gson.reflect.*;
import java.util.Map;
import java.util.HashMap;
import java.util.List;

public class Saving {

    public static void main(String[] args) {

        String json = "[[12], [13]]";
        json = json.trim();
        Map<Integer, List<Double>> fuelSavings = null;

        // such a cluster****
        if(json.startsWith("[[")) { // THERE HAS TO BE A BETTER WAY TO DO THIS PART
        // ANY WAY I CAN AVOID THIS ENTIRE IF CONDITION

            //implicit keys
            fuelSavings = new HashMap<Integer, List<Double>>();
            List<List<Double>> temporaryList = new Gson().fromJson(json, new TypeToken<List<List<Double>>>(){}.getType());
            int index = 0;
            for(List<Double> temporaryListMember: temporaryList) {
                fuelSavings.put(index, temporaryListMember);
                index++;
            }

        } else {

            // explicit keys
            // THIS PART IS PERFECT
            fuelSavings = new Gson().fromJson(json, new TypeToken<Map<Integer, List<Double>>>(){}.getType());

        }

        System.out.println(fuelSavings);

    }

}

Any help is appreciated, thanks!

What you do in PHP are two different things. Array in PHP serves as Arrays, Maps, Lists.

array(array(12), array(13)); and array("0" => array(12), "2" => array(13)); are not the same even in PHP.

What you need to do in Java using Gson is to parse the json as String and check whether the main object is a Map or a List and then advise. If you have loaded a List then you know it was a array(array(12), array(13)); otherwise it was the other one.

Can't you do something from the PHP side to generate it always the same?

Edit:

If you cannot do anything from the PHP side then your check will be identical to instantiate a JsonParser parse then checking if JsonObject.isJsonArray() returns true, except that it will be eventually quicker but you won't rely on the gson library.

Map<Integer, List<Double>> fuelSavings = null;
JsonElement jElement = new JsonParser().parse("[[12], [13]]");
JsonObject jObject = jelement.getAsJsonObject();
if (jObject.isJsonArray()) {
    fuelSavings = new HashMap<Integer, List<Double>>();
    List<List<Double>> temporaryList = new Gson().fromJson(jElement, new TypeToken<List<List<Double>>>(){}.getType());
    int index = 0;
    for(List<Double> temporaryListMember: temporaryList) {
        fuelSavings.put(index++, temporaryListMember);
    }
} else /* this is a map */ {
    fuelSavings = new Gson().fromJson(jElement, new TypeToken<Map<Integer, List<Double>>>(){}.getType());
}

Very interesting!

As I understood, PHP server serves its data as an ordered map encoded as JSON, but some times in a bad luck its keys are consecutive integers, which makes json_encode() understand it as a simple array and use a different format for the outputted JSON.

As I understand, all PHP arrays are ordered maps. But when one array has consecutive integer keys, json_encode() generates an array with no keys intead a "JSON Object" (map). And that breaks client's code that's not expecting an array instead of an "object".

Incredibly, I found no existing Java function to convert a JsonArray to a JsonObject , and we may even face some Exception sometimes if we try to get an array as an Object! Gosh, a JsonArray is just a JsonObject with implicit consecutive integer keys, it should be casted automatically!! :p

I didn't try it, but maybe JsonObject::entrySet() can solve it. It returns a Set<Map.Entry<String,JsonElement>> , which maybe may be converted to a Map<Integer, AnyObject> , if Integer parses String automatically and JsonElement can be converted with a proper TypeToken .

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