このページでは、Contraband の型システムを Java と Scala でエンコードする方法について説明します。
レコード型は、Scala の標準的な case クラスに対応する Java または Scala のクラスにマップされます。
標準的な case クラスにはじめにアクセスするのは便利ですが、バイナリ互換性を壊さずに新しいフィールドを追加することはできません。Contraband レコード (または準 case クラス) を使用すると、バイナリ互換性を壊さずに新しいフィールドを追加できるだけでなく、プレーン case クラスとほぼ同じ機能を使用できます。
package com.example
@target(Scala)
type Person {
name: String!
age: Int
}
このスキーマは、次の Scala クラスを生成します。
/**
* This code is generated using [[https://sbt.dokyumento.jp/contraband/ sbt-contraband]].
*/
// DO NOT EDIT MANUALLY
package com.example
final class Person private (
val name: String,
val age: Option[Int]) extends Serializable {
override def equals(o: Any): Boolean = o match {
case x: Person => (this.name == x.name) && (this.age == x.age)
case _ => false
}
override def hashCode: Int = {
37 * (37 * (17 + name.##) + age.##)
}
override def toString: String = {
"Person(" + name + ", " + age + ")"
}
private[this] def copy(name: String = name, age: Option[Int] = age): Person = {
new Person(name, age)
}
def withName(name: String): Person = {
copy(name = name)
}
def withAge(age: Option[Int]): Person = {
copy(age = age)
}
def withAge(age: Int): Person = {
copy(age = Option(age))
}
}
object Person {
def apply(name: String, age: Option[Int]): Person = new Person(name, age)
def apply(name: String, age: Int): Person = new Person(name, Option(age))
}
標準的な case クラスとは異なり、Contraband レコードは、バイナリ互換性に合う形で進化できない unapply
やパブリック copy
メソッドを実装しません。
copy
の代わりに、各フィールドに withX(...)
メソッドを生成します。
> val x = Person("Alice", 20)
> x.withAge(21)
生成する Java コードを次に示します (ターゲットアノテーションを Java
に変更後)。
/**
* This code is generated using [[https://sbt.dokyumento.jp/contraband/ sbt-contraband]].
*/
// DO NOT EDIT MANUALLY
package com.example;
public final class Person implements java.io.Serializable {
public static Person create(String _name, java.util.Optional<Integer> _age) {
return new Person(_name, _age);
}
public static Person of(String _name, java.util.Optional<Integer> _age) {
return new Person(_name, _age);
}
public static Person create(String _name, int _age) {
return new Person(_name, _age);
}
public static Person of(String _name, int _age) {
return new Person(_name, _age);
}
private String name;
private java.util.Optional<Integer> age;
protected Person(String _name, java.util.Optional<Integer> _age) {
super();
name = _name;
age = _age;
}
protected Person(String _name, int _age) {
super();
name = _name;
age = java.util.Optional.<Integer>ofNullable(_age);
}
public String name() {
return this.name;
}
public java.util.Optional<Integer> age() {
return this.age;
}
public Person withName(String name) {
return new Person(name, age);
}
public Person withAge(java.util.Optional<Integer> age) {
return new Person(name, age);
}
public Person withAge(int age) {
return new Person(name, java.util.Optional.<Integer>ofNullable(age));
}
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else if (!(obj instanceof Person)) {
return false;
} else {
Person o = (Person)obj;
return name().equals(o.name()) && age().equals(o.age());
}
}
public int hashCode() {
return 37 * (37 * (37 * (17 + "com.example.Person".hashCode()) + name().hashCode()) + age().hashCode());
}
public String toString() {
return "Person(" + "name: " + name() + ", " + "age: " + age() + ")";
}
}