Skip to content

ccheptea/auto-value-variant

Repository files navigation

AutoValue: Variant Extension Build Status

An extension for Google's AutoValue that generates a few handy methods to determine object variations based on statically defined variance groups.

The problem

Consider the following class:

@AutoValue abstract class Car{
    abstract String manufacturer();
    abstract String model();
    abstract String plateNumber();
    abstract int color();
    abstract String body();
}

Having a list of cars and a reference car, lets filter all the cars that have the manufacturer and model fields equal to the ones defined in our reference. Most probably we'll end up with some code similar to this:

Car ref = new AutoValue_Car("Tesla", "Model S", "", 0, "");
for(Car car : cars){
    boolean match = (ref.manufacturer() == null ? car.manufacturer() == null : ref.manufacturer().equals(car.manufacturer()))
        && (ref.model() == null ? car.model() == null : ref.model().equals(car.model()))
    
    if(match){
        filtered.add(car);
    }
}

This code is hard to read and maintain and can get worse if filters get more complex.

Variant definition

Short

Two objects are variants if they are of the same type and are not equal except for a set of their properties.

Long

Lets call an object A variant of object B if the followings apply:

  • A and B are of the same type
  • A and B have a set F of fields that are considered constant
  • Each property from F(A) equals to its corresponding property in F(B)
  • A.equals(B) returns false

Usage

AutoValue Variant has two key elements:

  • Variant interface, containing the methods for determining variants
  • @NonVariant annotation, applied to fields that we want to consider constant

Implement Variant, then apply the @NonVariant annotation on fields you want to consider constant.

@AutoValue abstract class Car implements Variant{
    @NonVariant abstract String manufacturer();
    @NonVariant abstract String model();
    abstract String plateNumber();
    abstract int color();
    abstract String body();
}

Then filtering will look like this:

for(Car car : cars){
    if(ref.like(car)){
        filtered.add(car);
    }
}
// or 
filtered = cars.stream().filter(car -> ref.like(car));

Multiple variant groups

You can define multiple variant groups by specifying the group name when applying the @NonVariant annotation

public abstract class Car implements Variant<Car> {

    @NonVariant(VariantGroups.IDENTITY)
    abstract String manufacturer();

    @NonVariant({VariantGroups.IDENTITY, VariantGroups.MODEL_AND_BODY})
    abstract String model();

    abstract String plateNumber();

    @NonVariant(VariantGroups.ASPECT)
    abstract int color();

    @NonVariant({VariantGroups.ASPECT, VariantGroups.MODEL_AND_BODY})
    abstract String body();

    static class VariantGroups {
        static final String IDENTITY = "identity";
        static final String ASPECT = "aspect";
        static final String MODEL_AND_BODY = "model_and_body";
    }
}

Then apply the like(Object, String) method

Car ref = new AutoValue_Car("Tesla", "Model S", "", 0xFF000000, "Sedan");

similarTeslaModelSCars = cars.stream().filter(car -> ref.like(car, Car.VariantGroups.IDENTITY));
blackSedans = cars.stream().filter(car -> ref.like(car, Car.VariantGroups.ASPECT));

Download

annotationProcessor 'com.ccheptea.auto.value:auto-value-variant:1.2.0'
compile 'com.ccheptea.auto.value:auto-value-variant-runtime:1.2.0'

Snapshots of the development version are available in Sonatype's snapshots repository.

Notes

The code for auto deploying artifacts with Travis as well as some of the extension code is based on or inspired by parts of:

License

Copyright 2017 Constantin Cheptea.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

About

AutoValue extension to easily determine variants for objects with known properties

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published