2017-08-17 18 views
10

はのは、データクラスのクラスを見てみましょう:Kotlinはゼロに引数にデフォルト値を設定し、コンストラクタを生成

data class User(
    val userNumber: Int = -1, 
    val name: String, 
    val userGroups; List<String> = emptyList(), 
    val screenName: String = "new-user" 
) 

Kotlinからこの関数を呼び出して、それは非常に簡単です。私は単純に名前付き引数の構文を使用してこれを行うことができます。 、今

User(int userNumber, @NotNull String name, @NotNull List userGroups, 
    @NotNull String screenName) 
User(int userNumber, @NotNull String name, @NotNull List userGroups) 
User(int userNumber, @NotNull String name) 
User(@NotNull String name) 

:ジャワからの呼び出し、私はすべての値を指定する必要があり、または(デフォルト値のビットマスクで生成kotlinコンストラクタに加えて)次のコンストラクタを生成@JvmOverloads注釈を使用します私がと同等のJavaでUserオブジェクトを作成したいのであれば、上記のコンストラクタではできません。私はval userNumber: Int = -1を末尾にdata class宣言(コンストラクタの生成はオプションの引数が定義されている順序に依存しているように見える)の末尾に置くとできます。これはうまくいきます。なぜなら、kotlinがすべての順列を生成することが、いくつかのクラスを大きく膨らませることになるからです。

彼らはコンストラクタが使用(と私は、特別に生成されたものの一つに注釈を付けることができます好きではない)する見当がつかないようJacksonのようなツールは、単に動作しない最大の問題。現在、私は、上記のアプローチを使用していますが、手動で、私はそれらを必要とするコンストラクタを定義する

User(Integer userNumber, String name, List<String> userGroups, String screenName) { 
    this.userNumber = (userNumber == null) ? -1 : userNumber; 
    this.userGroups = (userGroups == null) ? Collections.emptyList() : userGroups; 
    //... 
} 

だから、のような(単一)コンストラクタを生成する方法があります。署名の両方がJVM上で衝突しまうので、私は明らかに、同様のコンストラクタが動作しないの作成、明確にすべき

EDIT

。これは私の場合に欲しいものです:

また、プロパティのデフォルト値を2回書く必要があることにも注意してください。私はそれを見ているので、私はそこに解決策があるのか​​疑問だ。たぶんこれはkaptベースの私のサイドプロジェクトの良いユースケースです:

+1

あなたはジャクソン・モジュールkotlin(https://github.com/FasterXML/jackson-module-kotlin)を使用していますか?私はデフォルトのパラメータを持つコンストラクタを扱うことができると思います。 Javaでのあなたの問題については確かではありません。おそらく二次コンストラクタを使用しますか? – Strelok

+0

私はJavaには実際には問題はありませんが、jacksonでしかありません。あなたは正しいですが、私は単純に二次コンストラクタを使用できます(技術的には、上記の静的メソッドは二次コンストラクタに似ています)。チェックアウト 'jackson-module-kotlin' ... –

答えて

0

これを数分間キックした後、私はここでうまくいくかもしれない解決策を見つけたと思います。同じソースファイル内にトップレベルの関数を定義するだけで、オブジェクトをビルドすることができます。おそらく、そのよう:次に

fun build_user(userNumber: Int?, name: String, userGroups: List<String>?, screenName: String?) : User { 
    return User(if(userNumber !== null) userNumber else -1, name, if(userGroups !== null) userGroups else emptyList(), 
    if(screenName !== null) screenName else "new-user") 
} 

あなたがそれを必要とするとき、あなたは単に、Javaからそれを呼び出す:例から

User user = UserKt.build_user(null, "Hello", null, "Porterhouse Steak"); 
System.out.println(user); 

出力:

User(userNumber=-1, name=Hello, userGroups=[], screenName=Porterhouse Steak) 

メソッドがコンストラクタの間のどこかにあるのとビルダー。 Builderオブジェクトを完全に打ち破り、不要なJava-interopグルーコードの混乱を避けるためにdata classを混乱させるのを防ぎます。

詳細については、Package Level Functionsを参照してください。

+0

私の質問(編集部分)をチェックすれば、これはまさに私がやっていることです。トップレベルの機能を持つのではなく、単にクラス内に静的な機能があります。これによりjacksonの '@JsonCreator'で注釈を付けることができ、Javaからもこれを使用できます。問題は、これが作成する冗長性の量と、私が本質的にコンストラクタを書き直しているという事実であり、現在はこれら2つの点で指定されたデフォルト値が同じであることを確認することは私の責任です。 –

+0

プライマリコンストラクタからデフォルトを削除できませんか?コンパニオンファクトリメソッドは、オプションのパラメータを使用して構築するための唯一のルートである必要があります。 – AjahnCharles

1

より良い解決策は、ライブラリにKotlin機能を理解する可能性を追加することです。たとえば、ジャクソンの場合はjackson-module-kotlinが存在します。このライブラリでは、データクラスでデフォルト引数を使用できます。

例:

data class User(
     val userNumber: Int = -1, 
     val name: String, 
     val userGroups: List<String> = emptyList(), 
     val screenName: String = "new-user" 
) 

fun main(args: Array<String>) { 
    val objectMapper = ObjectMapper() 
      .registerModule(KotlinModule()) 

    val testUser = User(userNumber = 5, name = "someName") 

    val stringUser = objectMapper.writeValueAsString(testUser) 
    println(stringUser) 

    val parsedUser = objectMapper.readValue<User>(stringUser) 
    println(parsedUser) 

    assert(testUser == parsedUser) { 
     println("something goes wrong") 
    } 
} 
関連する問題