2

このビルダーを想定しましょう:

@NodeEntity
case class Meeting(@Indexed creator: String, @Indexed title: String, @Indexed description: String,
                 @Indexed activityType: String, @Indexed startSchedule: Date, @Indexed endSchedule: Date,
                 @Indexed place: String, @Indexed maxParticipants: Int) {

  @GraphId private var _id: Long = _

  private def this() {
    this("unknown", "no title", "no description", "no activity type", new Date(), new Date(), "no place", 0)
    //dummy values in order to satisfy Scala's no-arg constructor syntax (required by Spring-Data)
  }
}

object Meeting {

  def builder(): PossibleMeeting = PossibleMeeting()

  case class PossibleMeeting(creator: String = "", title: String = "", description: String = "",
                           activityType: String = "", schedule: (Date, Date) = (new Date(), new Date()),
                           place: String = "", maxParticipants: Int = 0) {

    def withCreator(creator: String) = {
        this.copy(creator = creator)
      }

      def withTitle(title: String) = {
        this.copy(title = title)
      }

      def withDescription(description: String) = {
        this.copy(description = description)
      }

      def withActivityType(activityType: String) = {
        this.copy(activityType = activityType)
      }

      def withSchedule(schedule: (Date, Date)) = {
        this.copy(schedule = schedule)
      }

      def withPlace(place: String) = {
        this.copy(place = place)
      }

      def withMaxParticipants(maxParticipants: Int) = {
        this.copy(maxParticipants = maxParticipants)
      }

      def build(validator: PossibleMeetingValidator) = {
        this.toMeeting(validator)
      }

    def toMeeting(possibleMeetingValidator: PossibleMeetingValidator): ValidationNEL[MeetingValidationError, Meeting] =
      (possibleMeetingValidator.checkForNonEmpty("creator", creator, "Creator must not be empty") |@|
        possibleMeetingValidator.checkForNonEmpty("title", title, "Title must not be empty") |@|
        possibleMeetingValidator.checkForNonEmpty("description", description, "Description must not be empty") |@|
        possibleMeetingValidator.checkForNonEmpty("activityType", activityType, "Activity type must not be empty") |@|
        possibleMeetingValidator.checkForEndScheduleConsistency("endSchedule", schedule._1, schedule._2, "Schedule is not consistent since endSchedule date is anterior to startSchedule date") |@|
        possibleMeetingValidator.checkForNonEmpty("place", place, "Place must not be empty"))(Meeting(_, _, _, _, schedule._1, _, _, maxParticipants))

  }

注釈は、オブジェクトをグラフ ノードとして保存するためにSpring-Data-Neo4j@NodeEntityによって使用されます。

クライアントにこの呼び出し構文を使用してMeeting:

Meeting.builder().
          withCreator(creator).
          withTitle(title).withDescription(description).
          withActivityType(activityType).
          withSchedule(schedule).withPlace(place).
          withMaxParticipants(maxParticipants).build(PossibleMeetingValidator())

リスクのある直接的な方法の代わりに:

Meeting(creator, title, description, activityType, schedule, place, maxParticipants)

case classここMeetingで、シールされたトレイトによって aを拡張し、Meetingプライベートにするという有名なトリックを試しました。このリンクはサンプルを示しています:リークを許可するケース クラスを非表示にします。

ただし、このソリューションでは、Spring-DataMeetingは、パブリック コンストラクター (パブリック クラス/ケース クラスを意味する) が必要であることを通知するエラーをスローします。

Spring-Data がアクセスについて文句を言わないように、ケース クラスを外部の直接使用から隠す別の方法はありますか? 不可能ではないにしても、非常に難しいように思えますが...それは素晴らしいことです:)

4

1 に答える 1

2

まあ、私が正しく理解していれば、これは要約すると、Spring が呼び出すことができるコンストラクターを持つことになりますが、scala コードは呼び出すことができません。私が見る1つの(醜い)解決策は、コンストラクターをシングルトンに対してプライベートにすることMeetingです。これにより、scala コード (シングルトン以外) がそれを直接インスタンス化できなくなります。一方、Java は「スコープ プライベート」の概念をサポートしていないため、コンストラクタは Java コードの観点からは実際にはパブリックです。特に、Java リフレクションを介してコンストラクターにアクセスする場合、コンストラクターは public として認識され、呼び出すことができます。これは、Spring が問題なくインスタンス化できることを意味しますMeetingが、同時に、scala コードはそれを直接インスタンス化できません。欲しいものだけ。

privateしたがって、あなたがしなければならないのはこれだけです(パラメータリストの前のキーワードに注意してください):

@NodeEntity
case class Meeting private[Meeting] (@Indexed creator: String, @Indexed title: String, @Indexed description: String,
             @Indexed activityType: String, @Indexed startSchedule: Date, @Indexed endSchedule: Date,
             @Indexed place: String, @Indexed maxParticipants: Int) {
 ...

これは期待どおりに機能するはずですが、scala コードから JVM モデルへの不完全なマッピングに依存するのは少し気の毒なことです。

別のよりクリーンな代替手段は、 を呼び出すカスタム ファクトリを使用して、Spring にクラスをインスタンス化する方法を教えることMetting.builderです。春の経験がないので、この解決策についてはこれ以上コメントしません。ただし、一見すると、次のものが関連しているようです: http://static.springsource.org/spring/docs/2.0.x/reference/beans.html#beans-factory-extension-factorybean

于 2013-02-22T12:08:05.870 に答える