2016-11-17 7 views
1

В Скале РЕПЛ следующий кодПочему scala.beans.beanproperty работать по-разному в искре

import scala.beans.BeanProperty 

class EmailAccount { 
    @scala.beans.BeanProperty var accountName: String = null 

    override def toString: String = { 
    return s"acct ($accountName)" 
    } 
} 
classOf[EmailAccount].getDeclaredConstructor() 

приводит

res0: java.lang.reflect.Constructor[EmailAccount] = public EmailAccount() 

однако в РЕПЛ искру, я получить

java.lang.NoSuchMethodException: EmailAccount.<init>() 
    at java.lang.Class.getConstructor0(Class.java:2810) 
    at java.lang.Class.getDeclaredConstructor(Class.java:2053) 
    ... 48 elided 

Что вызывает это несоответствие? Как я могу получить искру, чтобы соответствовать поведению искровой оболочки.

Я запустил консолей REPL, как так:

/home/placey/Downloads/spark-2.0.0-bin-hadoop2.7/bin/spark-shell --master local --jars /home/placey/snakeyaml-1.17.jar 

и

версий
scala -classpath "/home/placey/snakeyaml-1.17.jar 

Scala являются искра:

Using Scala version 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_55) 

Скала:

Welcome to Scala version 2.11.6 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_55). 

ответ

3

Собственно, это не относится к scala.beans.BeanProperty или даже к искр. Вы можете получить такое же поведение в стандартном Scala РЕПЛ, запустив его с -Yrepl-class-based параметра:

scala -Yrepl-class-based 

Теперь давайте попробуем определить простой пустой класс:

scala> class Foo() 
defined class Foo 

scala> classOf[Foo].getConstructors 
res0: Array[java.lang.reflect.Constructor[_]] = Array(public Foo($iw)) 

scala> classOf[Foo].getFields 
res1: Array[java.lang.reflect.Field] = Array(public final $iw Foo.$outer) 

Как вы можете видеть, РЕПЛ Изменив класс «на лету», добавив дополнительное поле и параметр в конструктор. Зачем?

Всякий раз, когда вы создаете или var в Scala REPL, он обернут в специальный объект, потому что в Scala нет такой вещи, как «глобальные переменные». См. this answer.

Обычно это объект, поэтому он доступен по всему миру. Однако с помощью -Yrepl-class-based REPL использует экземпляры классов вместо одного глобального объекта. Эта функция была введена разработчиками Spark, потому что Spark требует, чтобы классы были сериализуемыми, поэтому их можно отправить удаленному работнику (см. this pull request).

Из-за этого любой класс, который вы определяете в REPL, должен получить экземпляр $iw. В противном случае вы не сможете получить доступ к глобальным val и var, которые вы определили в REPL. Кроме того, сгенерированный класс автоматически расширяет Serializable.

Боюсь, что вы не можете ничего сделать, чтобы предотвратить это. spark-shell включает -Yrepl-class-based по умолчанию. Даже если бы была возможность отключить это поведение, вы столкнулись бы со многими другими проблемами, потому что ваши классы больше не будут сериализованы, но Spark должен их сериализовать.