Skip to content

Latest commit

 

History

History
326 lines (251 loc) · 11.2 KB

CHANGELOG.md

File metadata and controls

326 lines (251 loc) · 11.2 KB

Change log

This file summarises changes between major versions.

Version 3.0.1

This version features:

  • Updated dependencies
  • Added CommentPlaceholderRegistry

CommentPlaceholderRegistry

With this, you can register placeholders to be replaced in comments by AnnotationConfig whenever it creates a new config file.

Usage:

CommentPlaceholderRegistry.INSTANCE.registerPlaceholder("%foo%", "epic replacement");

Version 3.0.0

This version is all focused on serialization.

Introducing SimpleValueSerializer

This is a utility class to help you with serializing objects you do not need a custom serializer for in your own custom serializer of some kind. See the docs for more.

FieldTypeSerializer now is not exactly Field

Instead of passing a Field, AnnotationConfig now passes a SerializationContext, because AnnotationConfig can not always get a Field instance. We don't want to lie with another Field, instead, we are now focused on accurate data - what is it exactly (de)serializing. The other thing new we have - the AnnotationAccessor - this is a way of accessing a (perhaps) Field's annotations in a more controllable manner.

Better experience with FieldTypeSerializer?

Introducing the FieldTypeSerializer#functional(TriFunction, TriFunction) with which it shall be easier to create FieldTypeSerializers. Quick example:

// Before
SerializerRegistry.registerSerializer(Foo.class, new FieldTypeSerializer<Foo>() {
  
  @Override
  public Foo deserialize(DataObject data, SerializationContext<Foo> context, AnnotationAccessor annotations) {
    // deserialization logic
  }
  
  @Override
  public DataObject serialize(Foo value, SerializationContext<Foo> context, AnnotationAccessor annotations) {
    // serialization logic
  }
});

// After
SerializationRegistry.registerSerializer(
    Foo.class, 
        FieldTypeSerializer.<Foo>functional(
            (data, context, annotations) -> { // deserialization logic },
            (value, context, annotations) -> { // serialization logic }));

Beefed up default serializer

  • The default serializer now recognizes BigInteger and BigDecimal as "primitives" and (de)serializes them.
  • Fixed a few type mistakes on list (de)serialization, which caused everything to go to the default serializer rather than a proper serializer, if such is registered.
  • The default serializer now recognizes @Key and @Ignore annotations whenever (de)serializing an object.

CustomOptions and LoadSettings replaced

These two were confusing, so now they have been replaced with a unified Settings object which works together with the Setting interface. They can be used just as the objects they replaced, but with much better design.

Going smarter

Arrays

The default serializer now properly (de)serializes array types. Examples:

class MyConfig {
  
  private MyObj[] myObjArr = new MyObj[] { new MyObj("foo"), new MyObj("bar") };
  
  static class MyObj {
    
    String foo;
    
    MyObj(String foo) {
      this.foo = foo;
    }
    
    // serializer is not necessary
    static class Serializer implements FieldTypeSerializer<MyObj> {
      
      @Override
      public MyObj deserialize(DataObject data, SerializationContext<MyObj> context, AnnotationAccessor annotations) {
        return new MyObj(data.getAsString());
      }
      
      @Override
      public DataObject serialize(MyObj value, SerializationContext<MyObj> context, AnnotationAccessor annotations) {
        return new DataObject(value.foo);
      }
      
    }
    
  }
  
}

class Main {
  
  public static void main(String[] args) {
    MyConfig myConfig = new MyConfig();
    SerializerRegistry serializers = SerializerRegistry.INSTANCE;
    serializers.registerSerializer(MyConfig.MyObj.class, new MyConfig.MyObj.Serializer());
    YamlConfig.getConfigResolver().dump(myConfig, new File("config.yml"));
  }
  
}

The code above will output the following:

myObjArr: ["foo", "bar"]
Single field class logic

The default serializer now (de)serializes classes with only 1 field better. An example of usage for such class is a list where you may want some more redundancy.
Examples (YAML):

# Version 2.1.x:
foo:
  - bar: "zzz"

# Version 3.0.0:
foo:
  - "zzz"

Misc changes

  • Removed deprecated methods
  • Removed SerializerRegistry#registerSerializer(Class, BiFunction, BiFunction). Replaced by SerializerRegistry#registerSimpleSerializer(Class, Function, Function)
  • Quality-of-life code changes
  • Added a class called ReflectionUtils
  • Optimisations to MapUtils
  • Better preserve dump order
  • Added SerializerRegistry#registerSimpleValueSerializer(Class, Function) and SerializerRegistry#registerSimpleValueDeserializer(Class, Function)
  • Deprecation of DateSerializer in toml module.
  • Since not everything can be listed in the changelog, there have been many miscellaneous changes improving performance and API design. The full changes can be seen in the release commit(s).

Version 2.1.0

Comments inside sections

Now you are able to do comments inside sections. This required breaking the ValueWriter, but it's for good.

Version 2.0.1

Key resolver

You are able to resolve keys. There's a default resolver and implementation for dotted keys which you can use.

Misc changes

  • Simplified missing options generation

Version 2.0.0

Rewritten custom annotations

The previous implementation we had about custom annotations was messy and nobody could ever understand what is this/that for and why the hell does it need this/that.

The new implementation is pretty straightforward: custom annotations as of right now can only be used for validation of a given annotated field's deserialized value.

Example usage

// an annotation you have
public @interface MyAnnotation {}

// a class which implements AnnotationValidator
public class MyAnnotationValidator implements AnnotationValidator<MyAnnotation> {

  @Override
  public ValidationResponse validate(MyAnnotation annotation, Object value, CustomOptions options,
      Field field) {
    // value validation logic
  }

}

// then register the validator in the registry
CustomAnnotationRegistry.INSTANCE.register(MyAnnotation.class, new MyAnnotationValidator());

Change FieldTypeResolver and @TypeResolver logic

The previous system was hard to understand because the FieldTypeResolver had some unnecessary stuff. This new system is much better, trust me!

The @TypeResolver annotation was removed and replaced by a SerializerRegistry.
The FieldTypeResolver was renamed to FieldTypeSerializer, generalized and with methods changed to serialize and deserialize.
This means faster to type resolvers and much more control over what the library dumps in a config file and what it resolves to.
Another cool thing is that the default serializer handles enums, maps and lists, and you won't need to create specific serializers for them.

Example usage

// an object you have
public class Location {

  private String world;
  private int x, y, z;

  public Location(String world, int x, int y, int z) {
    this.world = world;
    this.x = x;
    this.y = y;
    this.z = z;
  }

  // getters
}

  // this is in your base config
  // of course the annotations aren't mandatory
  @Comment("Location of player")
  @Key("player-location")
  private Location location = new Location("world", 20, 2, 1);

// the serializer
public class LocationSerializer implements FieldTypeSerializer<Location> {

  @Override
  public Location deserialize(DataObject data, Field field) {
    return new Location(
        data.get("world").getAsString(),
        data.get("x").getAsInt(),
        data.get("y").getAsInt(),
        data.get("z").getAsInt()
    );
  }

  @Override
  public DataObject serialize(Location value, Field field) {
    DataObject object = new DataObject();
    object.put("world", value.getWorld());
    object.put("x", value.getX());
    object.put("y", value.getY());
    object.put("z", value.getZ());
    return object;
  }

}

// this should be run before you load the config
SerializerRegistry.INSTANCE.registerSerializer(Location.class,new LocationSerializer());

Or, you can let the default config serializer handle serialization and deserialization. The default implementation is pretty good and there's no additional need for annotations or special constructors. All you need is a simple object with set fields and you're good to go!

A way to implement new config types

In 1.0, if you wanted other than the already implemented config types, you'd have to dive into the internal class AnnotatedConfigResolver and figure out how to implement it. Plus the thing that it required implementation of the interface called ValueWriter. This was an inner interface for AnnotatedConfigResolver, which made it even harder. No more!

In version 2.0.0 it was added a proper API called ConfigResolver to interact with this internal class. Also, ValueWriter interface got exposed from AnnotatedConfigResolver to its own class. Everything has been documented with lots of information, so you can more easily create them, and so you don't do something wrong.

You can also add custom options to a ConfigResolver to be accessed by the config reader and writer.

Example usage

    ConfigResolver resolver =
        ConfigResolver.newBuilder()
            .withValueReader(/* value reader */)
            .withValueWriter(/* value writer */)
            .withCommentPrefix("# " /* the implemented config type's comment prefix */)
            .shouldReverseFields(
                true /* in some config types it is needed to reverse the fields so everything is in order with the config object we're reading from */)
            .build();
    // do stuff with the resolver instance

New Annotations

There are two new annotations - @Min and @Max . They can be applied on String values and numbers. If applied on a number, they will validate the number ; if on a String, they will validate the string's length.

Specific TOML changes

mwanji/toml4j has been replaced with FasterXML/jackson-dataformats-text (toml module), meaning if you have used a custom TomlWriter from toml4j, it needs to be migrated to the TomlMapper of jackson-dataformats-toml.

Misc changes

Here are the changes that don't need too much attention, but are still important.

  • AnnotationType is now an enum and has been moved to annotationconfig.core.annotations.type
  • Retrieve annotation was renamed to Ignore for more clearance
  • Annotations are in separate package, annotationconfig.core.annotations, the comment annotations are under annotations.comment
  • The library now completely generates all kinds of config options if they are missing in an existing config.
  • Fixed a special case bug where @Key annotations aren't respected for fields annotated with @ConfigObject.
  • Handle fields which aren't annotated at all.