AutoValue

AutoValue ์ ์šฉํ•ด๋ณด๊ธฐ

AutoValue๋Š” ์ฝ”๋“œ ์ž๋™ ์ƒ์„ฑ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ์ž๋ฐ” ์ฝ”๋“œ๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ์œผ๋ฉฐ, AutoValue๋Š” Reflection์„ ์ด์šฉํ•œ ๋Ÿฐํƒ€์ž„ ๋ฐฉ์‹์ด ์•„๋‹Œ apt๋ฅผ ์ด์šฉํ•˜์—ฌ ์ปดํŒŒ์ผ ํƒ€์ž„์— ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์— ์„ฑ๋Šฅ์ƒ์— ๋ถˆ์ด์ต์€ ์—†๋‹ค.

google AutoValue์—์„œ jarํŒŒ์ผ์„ ๋‹ค์šด๋กœ๋“œ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.

๋งŒ์•ฝ maven์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” pom.xml์— dependency๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

<dependencies>
    <dependency>
        <groupId>com.google.auto.value</groupId>
        <artifactId>auto-value</artifactId>
        <version>1.3</version>
    </dependency>
</dependencies>
image-20210202224222521

๋‹ค์šด๋กœ๋“œ ๋ฐ›์€ jarํŒŒ์ผ์€ intellij project settings > Libraries์— ์ถ”๊ฐ€ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

์šฐ์„  @AutoValue ๋ฅผ ์‚ดํŽด๋ณด๋ฉด, ๋‚ด๋ถ€์— ์˜ˆ์‹œ์™€ ํ•จ๊ป˜ AutoValue github ์ฃผ์†Œ๋ฅผ ์•Œ๋ ค์ฃผ๊ณ  ์žˆ๋‹ค.

/**
 * Specifies that <a href="https://github.com/google/auto/tree/master/value">AutoValue</a> should
 * generate an implementation class for the annotated abstract class, implementing the standard
 * {@link Object} methods like {@link Object#equals equals} to have conventional value semantics. A
 * simple example: <pre>
 *
 *   @AutoValue
 *   abstract class Person {
 *     static Person create(String name, int id) {
 *       return new AutoValue_Person(name, id);
 *     }
 *
 *     abstract String name();
 *     abstract int id();
 *   }</pre>
 *
 * @see <a href="https://github.com/google/auto/tree/master/value">AutoValue User's Guide</a>
 *
 * @author ร‰amonn McManus
 * @author Kevin Bourrillion
 */
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface AutoValue {

  /**
   * Specifies that AutoValue should generate an implementation of the annotated class or interface,
   * to serve as a <i>builder</i> for the value-type class it is nested within. As a simple example,
   * here is an alternative way to write the {@code Person} class mentioned in the {@link AutoValue}
   * example: <pre>
   *
   *   @AutoValue
   *   abstract class Person {
   *     static Builder builder() {
   *       return new AutoValue_Person.Builder();
   *     }
   *
   *     abstract String name();
   *     abstract int id();
   *
   *     &#64;AutoValue.Builder
   *     interface Builder {
   *       Builder name(String x);
   *       Builder id(int x);
   *       Person build();
   *     }
   *   }</pre>
   *
   * @author ร‰amonn McManus
   */
  @Retention(RetentionPolicy.SOURCE)
  @Target(ElementType.TYPE)
  public @interface Builder {}

  /**
   * Specifies that AutoValue should copy any annotations from the annotated element to the
   * generated class. This annotation supports classes and methods.
   *
   * <p>The following annotations are excluded:
   *
   * <ol>
   * <li>AutoValue and its nested annotations;
   * <li>any annotation appearing in the {@link AutoValue.CopyAnnotations#exclude} field;
   * <li>any class annotation which is itself annotated with the
   *     {@link java.lang.annotation.Inherited} meta-annotation.
   * </ol>
   *
   * <p>When the <i>type</i> of an {@code @AutoValue} property method has annotations, those are
   * part of the type, so they are always copied to the implementation of the method.
   * {@code @CopyAnnotations} has no effect here. For example, suppose {@code @Confidential} is a
   * {@link java.lang.annotation.ElementType#TYPE_USE TYPE_USE} annotation: <pre>
   *
   *   &#64;AutoValue
   *   abstract class Person {
   *     static Person create(&#64;Confidential String name, int id) {
   *       return new AutoValue_Person(name, id);
   *     }
   *
   *     abstract &#64;Confidential String name();
   *     abstract int id();
   *   }</pre>
   *
   * Then the implementation of the {@code name()} method will also have return type
   * {@code @Confidential String}.
   *
   * @author Carmi Grushko
   */
  @Retention(RetentionPolicy.SOURCE)
  @Target({ElementType.TYPE, ElementType.METHOD})
  public @interface CopyAnnotations {
    Class<? extends Annotation>[] exclude() default {};
  }
}

๊ฐ€์ด๋“œ๋ผ์ธ์„ ๊ธฐ์ค€์œผ๋กœ ํด๋ž˜์Šค ํ•œ๊ฐœ๋ฅผ ์ƒ์„ฑํ•ด ๋ณผ ๊ฒƒ์ด๋‹ค.

@AutoValue
public abstract class Product {
    public abstract String name();
    public abstract BigDecimal price();

    @AutoValue.Builder
    public abstract static class Builder{
        public abstract Builder name(String name);
        public abstract Builder price(BigDecimal price);
        public abstract Product build();
    }

    public static Product.Builder builder(){
        return new AutoValue_Product.Builder();
    }
}
image-20210202225517078

AutoValue ์–ด๋…ธํ…Œ์ด์…˜์„ ์„ค์ •ํ•˜์ง€ ์•Š์œผ๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

image-20210202225749535

Compiler > Annotation Processors์—์„œ Enable annotation processing์„ ์ฒดํฌํ•ด์ค€๋‹ค. ๊ทธ๋ฆฌ๊ณ  modules์˜ dependencies์— auto-value ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ํฌํ•จ๋˜์–ด์žˆ์ง€ ์•Š๋‹ค๋ฉด ๋ณ„๋„๋กœ ์ถ”๊ฐ€ํ•ด์ค˜์•ผํ•œ๋‹ค.

image-20210202230221276

๋ชจ๋‘ ์ถ”๊ฐ€ํ•œ ๋’ค์— project rebuild๋ฅผ ํ•˜๋ฉด AutoValue_Product๊ฐ€ ์ƒ์„ฑ๋œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

image-20210202231607412

๋‹ค์‹œ ์ฝ”๋“œ๋ฅผ ํ•˜๋‚˜ํ•˜๋‚˜ ์ง‘์–ด๋ณผ ๊ฒƒ์ด๋‹ค.

@AutoValue
public abstract class Product {
    public abstract String name();
    public abstract BigDecimal price();

    @AutoValue.Builder
    public abstract static class Builder{
        public abstract Builder name(String name);
        public abstract Builder price(BigDecimal price);
        public abstract Product build();
    }

    public static Product.Builder builder(){
        return new AutoValue_Product.Builder();
    }
}
  • @AutoValue ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํด๋ž˜์Šค๋Š” abstract(์ถ”์ƒ) ํด๋ž˜์Šค์ด๋ฉฐ, ์‹ค์ œ๋กœ ๊ตฌํ˜„ํ•˜๋Š” ํด๋ž˜์Šค๋Š” builder() ๋ถ€๋ถ„์˜ AutoValue_Product ์ด๋‹ค.

  • ์•ˆ์˜ ํด๋ž˜์Šค ๋ฉค๋ฒ„ ๋ณ€์ˆ˜๋„ abstract ์ถ”์ƒํ•จ์ˆ˜๋กœ ์„ ์–ธ๋˜์–ด์žˆ๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„ ์–ธํ•ด์ฃผ๋ฉด AutoValue_Product ํด๋ž˜์Šค์— ๋ณ€์ˆ˜๊ฐ€ ์ƒ์„ฑ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

import java.math.BigDecimal;

final class AutoValue_Product extends Product {
    private final String name;
    private final BigDecimal price;

    private AutoValue_Product(String name, BigDecimal price) {
        this.name = name;
        this.price = price;
    }

    public String name() {
        return this.name;
    }

    public BigDecimal price() {
        return this.price;
    }

    public String toString() {
        return "Product{name=" + this.name + ", price=" + this.price + "}";
    }

    public boolean equals(Object o) {
        if (o == this) {
            return true;
        } else if (!(o instanceof Product)) {
            return false;
        } else {
            Product that = (Product)o;
            return this.name.equals(that.name()) && this.price.equals(that.price());
        }
    }

    public int hashCode() {
        int h = 1;
        int h = h * 1000003;
        h ^= this.name.hashCode();
        h *= 1000003;
        h ^= this.price.hashCode();
        return h;
    }

    static final class Builder extends ch3.dahye.item11.Product.Builder {
        private String name;
        private BigDecimal price;

        Builder() {
        }

        public ch3.dahye.item11.Product.Builder name(String name) {
            if (name == null) {
                throw new NullPointerException("Null name");
            } else {
                this.name = name;
                return this;
            }
        }

        public ch3.dahye.item11.Product.Builder price(BigDecimal price) {
            if (price == null) {
                throw new NullPointerException("Null price");
            } else {
                this.price = price;
                return this;
            }
        }

        public Product build() {
            String missing = "";
            if (this.name == null) {
                missing = missing + " name";
            }

            if (this.price == null) {
                missing = missing + " price";
            }

            if (!missing.isEmpty()) {
                throw new IllegalStateException("Missing required properties:" + missing);
            } else {
                return new AutoValue_Product(this.name, this.price);
            }
        }
    }
}
public class item11 {
    public static void main(String[] args) {
        Product product = Product.builder().price(new BigDecimal(990000)).name("autoValue").build();
        System.out.println(product); // Product{name=autoValue, price=990000}
    }
}
image-20210202232027493

๋‹ค์Œ๊ณผ ๊ฐ™์ด Product ํด๋ž˜์Šค๋ฅผ builder๋กœ ์ƒ์„ฑํ•˜๋ฉด, AutoValue_Product ์ธ์Šคํ„ด์Šค๋กœ ์ƒ์„ฑ๋œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. AutoValue๋Š” ๋ถˆ๋ณ€์ •๋ณด(Immutable)๋ฅผ ์ „๋‹ฌํ•˜๋Š” ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ• ๋•Œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. AutoValue_Product๋ฅผ ๋ณด๋ฉด final ํด๋ž˜์Šค์ด๋ฉด์„œ ๋ณ€์ˆ˜๋„ final ์ธ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ, AutoValue๋Š” ๋ฉค๋ฒ„ ๋ณ€์ˆ˜ ๊ฐ’์ด ํ•ญ์ƒ ๋ฐ”๋€” ์ˆ˜ ์žˆ๋Š” ์ธ์Šคํ„ด์Šค์—์„œ๋Š” ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ๋œ๋‹ค.

์ฐธ์กฐ

Last updated

Was this helpful?