如何使用Gson序列化特殊的json(对象的instand内容)

时间:2018-05-30 09:32:47

标签: java json serialization gson

我使用Java + Gson,我希望序列化一个特殊的json。我想要对象的对象instand的内容。

a*b/c

是否可以序列化为:

import ctypes
import time

# C struct redefinitions 
PUL = ctypes.POINTER(ctypes.c_ulong)
class KeyBdInput(ctypes.Structure):
    _fields_ = [("wVk", ctypes.c_ushort),
                ("wScan", ctypes.c_ushort),
                ("dwFlags", ctypes.c_ulong),
                ("time", ctypes.c_ulong),
                ("dwExtraInfo", PUL)]

class HardwareInput(ctypes.Structure):
    _fields_ = [("uMsg", ctypes.c_ulong),
                ("wParamL", ctypes.c_short),
                ("wParamH", ctypes.c_ushort)]

class MouseInput(ctypes.Structure):
    _fields_ = [("dx", ctypes.c_long),
                ("dy", ctypes.c_long),
                ("mouseData", ctypes.c_ulong),
                ("dwFlags", ctypes.c_ulong),
                ("time",ctypes.c_ulong),
                ("dwExtraInfo", PUL)]

class Input_I(ctypes.Union):
    _fields_ = [("ki", KeyBdInput),
                 ("mi", MouseInput),
                 ("hi", HardwareInput)]

class Input(ctypes.Structure):
    _fields_ = [("type", ctypes.c_ulong),
                ("ii", Input_I)]

# Actuals Functions
def MouseMoveTo(x, y):
    extra = ctypes.c_ulong(0)
    ii_ = Input_I()
    ii_.mi = MouseInput(x, y, 0, 0x0001, 0, ctypes.pointer(extra))

    command = Input(ctypes.c_ulong(0), ii_)
    ctypes.windll.user32.SendInput(1, ctypes.pointer(command), ctypes.sizeof(command))

我尝试使用此代码但错误:

{
    "age": 26,
    "email": "norman@futurestud.io",
    "isDeveloper": true,
    "name": "Norman",

    "userAddress": {
        "city": "Magdeburg",
        "country": "Germany",
        "houseNumber": "42A",
        "street": "Main Street"
    }
}

2 个答案:

答案 0 :(得分:0)

您正在寻找JSON树。 但至少有一点需要注意的是在不同的对象中共享同名的属性名称。

假设您有以下数据类:

final class User {

    final String email;
    final String name;
    final int age;
    final boolean isDeveloper;

    User(final String email, final int age, final String name, final boolean isDeveloper) {
        this.age = age;
        this.email = email;
        this.isDeveloper = isDeveloper;
        this.name = name;
    }

    @Override
    public String toString() {
        return MoreObjects.toStringHelper(this)
                .add("email", email)
                .add("name", name)
                .add("age", age)
                .add("isDeveloper", isDeveloper)
                .toString();
    }

}
final class UserAddress {

    final String country;
    final String city;
    final String street;
    final String houseNumber;

    UserAddress(final String country, final String city, final String street, final String houseNumber) {
        this.country = country;
        this.city = city;
        this.street = street;
        this.houseNumber = houseNumber;
    }

    @Override
    public String toString() {
        return MoreObjects.toStringHelper(this)
                .add("country", country)
                .add("city", city)
                .add("street", street)
                .add("houseNumber", houseNumber)
                .toString();
    }

}

现在,您可以使用实用程序方法将多个对象序列化为单个JsonObject实例。 此外,您可以轻松地使用反序列化计数器部件,该部件可以从JsonObject实例反序列化多个对象。 例如:

final class JsonObjects {

    private JsonObjects() {
    }

    @SafeVarargs
    static JsonObject combine(final Gson gson, final Map.Entry<Object, ? extends Type>... objectAndTypeEntries) {
        return Stream.of(objectAndTypeEntries)
                // Each element should be serialized to a JsonElement
                .map(e -> gson.toJsonTree(e.getKey(), e.getValue()))
                // That must be a JSON object
                .map(JsonElement::getAsJsonObject)
                // And now we can collect a stream of JsonObject instances into a super-object
                .collect(Collector.of(
                        JsonObject::new, // We'll collect into a new JsonObject instance, this is the accumulator
                        JsonObjects::mergeInto, // Merge each consecutive JsonObject instance into the accumulator
                        JsonObjects::mergeInto, // Or even combine multiple accumulators
                        Function.identity() // And just return the accumulator
                ));
    }

    static List<?> split(final Gson gson, final JsonObject jsonObject, final Type... types) {
        return Stream.of(types)
                // Each element should be deserialized from the JsonObject by a type
                .map(type -> gson.fromJson(jsonObject, type))
                // And just collect all the deserialized objects to a list
                .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
    }

    private static JsonObject mergeInto(final JsonObject to, final JsonObject from) {
        for ( final Map.Entry<String, JsonElement> e : from.entrySet() ) {
            to.add(e.getKey(), e.getValue());
        }
        return to;
    }

}

使用示例:

final User beforeUser = new User("norman@localhost", 26, "Norman", true);
System.out.println("BEFORE User: " + beforeUser);
final UserAddress beforeUserAddress = new UserAddress("Germany", "Magdeburg", "Main Street", "42A");
System.out.println("BEFORE User address: " + beforeUserAddress);
final JsonObject jsonObject = JsonObjects.combine(
        gson,
        new AbstractMap.SimpleImmutableEntry<>(beforeUser, User.class),
        new AbstractMap.SimpleImmutableEntry<>(beforeUserAddress, UserAddress.class)
);
System.out.println("JSON: " + jsonObject);
final List<?> objects = JsonObjects.split(gson, jsonObject, User.class, UserAddress.class);
final User afterUser = (User) objects.get(0);
System.out.println("AFTER User: " + afterUser);
final UserAddress afterUserAddress = (UserAddress) objects.get(1);
System.out.println("AFTER User address: " + afterUserAddress);

输出:

BEFORE User: User{email=norman@localhost, name=Norman, age=26, isDeveloper=true}
BEFORE User address: UserAddress{country=Germany, city=Magdeburg, street=Main Street, houseNumber=42A}
JSON: {"email":"norman@localhost","name":"Norman","age":26,"isDeveloper":true,"country":"Germany","city":"Magdeburg","street":"Main Street","houseNumber":"42A"}
AFTER User: User{email=norman@localhost, name=Norman, age=26, isDeveloper=true}
AFTER User address: UserAddress{country=Germany, city=Magdeburg, street=Main Street, houseNumber=42A}

正如您所看到的,您不需要创建额外的DTO类来涵盖所有情况,但由于在这里使用了树,这也需要更多的内存使用。

答案 1 :(得分:0)

我找到了一个使用Gson工具的解决方案(类UserAddressAdapter extends TypeAdapter<UserAddress>)。

public class User {

    ...

    // see the first ligne of UserAddressAdapter#write
    // city => (out.value(value.getCity());)
    @SerializedName("city")
    @JsonAdapter(UserAddressAdapter.class)
    private final UserAddress userAddress;
    ...

}


public class UserAddressAdapter extends TypeAdapter<UserAddress> {

    @Override
    public void write(JsonWriter out, UserAddress value) throws IOException {
        out.value(value.getCity());
        out.name("country");
        out.value(value.getCountry());
        out.name("houseNumber");
        out.value(value.getHouseNumber());
        out.name("street");
        out.value(value.getStreet());
    }

    @Override
    public UserAddress read(JsonReader in) throws IOException {
        final int city = in.nextInt();
        UserAddress[] scopes = UserAddress.values();
        for (UserAddress scope : scopes) {
            if (scope.getCity() == city) {
                return scope;
            }
        }
        return null;
    }

}

和来电者是:

new Gson().toJson(new User("...", ...))