OkaeriPoland / okaeri-configs

Simple Java/POJO config library written with love and Lombok
MIT License
83 stars 11 forks source link

Give access to root object in serializer #38

Closed P3ridot closed 1 year ago

P3ridot commented 1 year ago

I'd like to access root object in serializer. I'll give an exmaple:

I have object... For eg. ComplexMessage that contains ChatMessage & ActionbarMessage . In normal serializer I would serialize it to something like that:

message:
  chat: "Chat message"
  actionbar: "Actionbar message"

which is fine when I have 2 messages types used

But when I have only 1 message type (for eg. chat) I ends up with

message:
  chat: "Chat message"

but I wants it's to be simpler - and serialize it as String:

message: "Chat message"
dasavick commented 1 year ago

Try 4.0.10-beta.1. Note that getAsList and getAsMap analogs are currently unavailable.

public class LocationSerializer implements ObjectSerializer<Location> {

    @Override
    public boolean supports(@NonNull Class<? super Location> type) {
        return Location.class.isAssignableFrom(type);
    }

    @Override
    public void serialize(@NonNull Location location, @NonNull SerializationData data, @NonNull GenericsDeclaration generics) {

        data.setValue((location.getWorld() == null ? null : location.getWorld().getName()) + " " + location.getX() + " " + location.getY()
                + " " + location.getZ() + " " + location.getYaw() + " " + location.getPitch());

//        data.add("world", location.getWorld(), World.class);
//        data.add("x", location.getX());
//        data.add("y", location.getY());
//        data.add("z", location.getZ());
//        data.add("yaw", location.getYaw());
//        data.add("pitch", location.getPitch());
    }

    @Override
    public Location deserialize(@NonNull DeserializationData data, @NonNull GenericsDeclaration generics) {

        if (data.hasValue()) {

            String valueString = data.getValue(String.class);
            String[] parts = valueString.split(" ");

            World world = data.getConfigurer().resolveType(
                parts[0],
                GenericsDeclaration.of(String.class),
                World.class,
                GenericsDeclaration.of(World.class),
                SerdesContext.of(data.getConfigurer())
            );

            double x = Double.parseDouble(parts[1]);
            double y = Double.parseDouble(parts[2]);
            double z = Double.parseDouble(parts[3]);
            float yaw = Float.parseFloat(parts[4]);
            float pitch = Float.parseFloat(parts[5]);

            return new Location(world, x, y, z, pitch, yaw);
        }

        World world = data.get("world", World.class);
        double x = data.get("x", Double.class);
        double y = data.get("y", Double.class);
        double z = data.get("z", Double.class);
        float yaw = data.get("yaw", Float.class);
        float pitch = data.get("pitch", Float.class);

        return new Location(world, x, y, z, pitch, yaw);
    }
}
P3ridot commented 1 year ago

Note that getAsList and getAsMap analogs are currently unavailable.

So currently I can achieve

message: "String"

but not:

message: 
- "Line 1"
- "Line 2"

Right?

dasavick commented 1 year ago

The getAsList and the getAsMap is only a shortcut to a specific Configurer#resolveType call. These can always be performed using getDirect(key, GenericsDeclaration) or getValueDirect(GenericsDeclaration).

The getValueAsMap method will never make sense because if the object is interpretable as Map it is deconstructed and passed as standard DeserializationData. The getValueAsList will be available in the release version.

    public <T> T getDirect(@NonNull String key, @NonNull GenericsDeclaration genericType) {
        Object object = this.data.get(key);
        return (T) this.configurer.resolveType(object, null, genericType.getType(), genericType, SerdesContext.of(this.configurer));
    }
    public <T> T getValueDirect(@NonNull GenericsDeclaration genericType) {
        return this.getDirect(ObjectSerializer.VALUE, genericType);
    }

There is nothing preventing you from calling getAsList(ObjectSerializer.VALUE, Class) which will be the implementation of previously mentioned getValueAsList(Class).

    public <T> List<T> getAsList(@NonNull String key, @NonNull Class<T> listValueType) {
        GenericsDeclaration genericType = GenericsDeclaration.of(List.class, Collections.singletonList(listValueType));
        return (List<T>) this.getAsCollection(key, genericType);
    }
    public <T> Collection<T> getAsCollection(@NonNull String key, @NonNull GenericsDeclaration genericType) {
        if (!Collection.class.isAssignableFrom(genericType.getType())) {
            throw new IllegalArgumentException("genericType.type must be a superclass of Collection: " + genericType);
        }
        return this.getDirect(key, genericType);
    }
dasavick commented 1 year ago

The getValueAsList will be available in the release version.

Well, the getValueAsList(Class) is now available in 4.0.10-beta.2 since I decided Deserialization#hasValue should be renamed to Deserialization#isValue to avoid potential confusion.

dasavick commented 1 year ago

Mostly complete API available staring from 5.0.0-beta.1.

image

image