2011-02-07 1 views
2

В контексте Eclipse Databinding существует немало классов Java, которые действуют как фабрики для объектов IObservable. Например, есть BeanObservables, PojoObservables, EMFObservables и т.д., и все они реализуют набор методов, подобногоКак сохранить ссылку на набор статических методов Java из Scala?

public static IObservableValue observeValue(Object target, String property) 

Теперь, если мы были в мире Scala, каждый из этих заводов, вероятно, будет одноэлементен объектом, реализующий общий признак, скажем, IObservableFactory, и я мог бы, например, передать их как неявные значения методам, которые будут использовать их для создания привязок данных.

Но поскольку они определены на Java, кажется, я ничего не могу сделать. Я не могу писать

val pojoObservableFact = PojoObservables 

потому PojoObservables не признается в качестве значения.

Есть ли способ заставить компилятор «создать экземпляр» синглета, который будет соответствовать классу PojoObservables в Scala? Или любое обходное решение для этого? Я знаю, что могу написать сам синглтон и направить все вызовы методов, но это звучит немного утомительно.


Редактировать

Чтобы было понятнее: это то, что я пытаюсь сделать: определить метод, который создает наблюдаемое значение с помощью проходной завода.

def createObservable(fact: ObservableFactory, target: AnyRef, property: String) = 
    fact.observeValue(target, property) 

, но я не знаю, как определить ObservableFactory или как на самом деле проходит PojoObservables, класс Java с только статическими методами, к этому createObservable методы.

ответ

4

Если никто больше не приходит с рабочим ответ, я не думаю, что это было бы все, что трудно написать генератор кода на основе сигнатур методов.

val a = classOf[String].getMethods.map(_.toString).filter(s => 
    s.contains("public") && s.contains("static") 
) 

будет, например, вытащить все сигнатуры методов (для String в данном случае) в виде строк. Затем

val b = a.map(_.split(" ").reverse.take(2).reverse) 

будет захватывать только функцию с типом возврата, разделенным спереди. Теперь

val c = b.map(_(1).dropWhile(_ != '(').drop(1).takeWhile(_ != ')').split(",")) 
val d = b.map(_(1).takeWhile(_ != '(')) 

будет получать подписи и имя функции, соответственно. Затем нам нужно преобразовать примитивные типы, которые довольно легко, так как нам просто нужно заглавной буквы (за исключением пустоты, которая становится блок):

def jprim2scala(s: String) = { 
    val prim = List("boolean","byte","short","char","int","long","float","double") 
    def arrayconvert(s: String): String = { 
    if (s.endsWith("[]")) "Array["+arrayconvert(s.substring(0,s.length-2))+"]" 
    else if (s=="void") "Unit" 
    else if (prim contains s) { 
     s.substring(0,1).toUpperCase + s.substring(1) 
    } 
    else s 
    } 
    arrayconvert(s) 
} 

def e = (b,c).zipped.map((bi,ci) => (jprim2scala(bi(0)), ci.map(jprim2scala))) 

и, наконец, вы можете положить все это вместе:

val f = (d,e).zipped.map((name,ei) => { 
    val (ret,args) = ei 
    val lastname = name.split('.').last 
    "def "+lastname+"(" + 
    (for ((a,i) <- args.zipWithIndex) yield ("a"+i+": "+a)).mkString(", ") + 
    "): "+ret+" = "+name+"("+(0 until args.length).map("a"+_).mkString(",")+")" 
}) 

Теперь у вас есть куча кода Scala, который вы можете поместить (вручную) в подходящий синглтон.

object Stringleton { 
    // The contents of this is cut-and-paste f.map(" "+_).foreach(println) 
    def valueOf(a0: java.lang.Object): java.lang.String = java.lang.String.valueOf(a0) 
    def valueOf(a0: Array[Char]): java.lang.String = java.lang.String.valueOf(a0) 
    def valueOf(a0: Array[Char], a1: Int, a2: Int): java.lang.String = java.lang.String.valueOf(a0,a1,a2) 
    def valueOf(a0: Boolean): java.lang.String = java.lang.String.valueOf(a0) 
    def valueOf(a0: Char): java.lang.String = java.lang.String.valueOf(a0) 
    def valueOf(a0: Int): java.lang.String = java.lang.String.valueOf(a0) 
    def valueOf(a0: Long): java.lang.String = java.lang.String.valueOf(a0) 
    def valueOf(a0: Float): java.lang.String = java.lang.String.valueOf(a0) 
    def valueOf(a0: Double): java.lang.String = java.lang.String.valueOf(a0) 
    def copyValueOf(a0: Array[Char], a1: Int, a2: Int): java.lang.String = java.lang.String.copyValueOf(a0,a1,a2) 
    def copyValueOf(a0: Array[Char]): java.lang.String = java.lang.String.copyValueOf(a0) 
    def format(a0: java.lang.String, a1: Array[java.lang.Object]): java.lang.String = java.lang.String.format(a0,a1) 
    def format(a0: java.util.Locale, a1: java.lang.String, a2: Array[java.lang.Object]): java.lang.String = java.lang.String.format(a0,a1,a2) 
} 

(переменные аргументы не работают здесь, кстати - you'd нужно, чтобы исправить их, если они присутствовали Вы можете сделать это, возвращаясь к методу .isVarArgs от самого метода (а не его строковое представление.) и преобразование последнего массива [X] в X *, а затем называет его ai: _*.)

Приятная вещь в этом подходе состоит в том, что если существуют общие методы, вам даже не нужно использовать структурную типизацию в порядке вытащить их - вы можете определить свою собственную черту, которую наследуют ваши обернутые методы! (И если вы особенно амбициозны, вы можете обучать практически, но не совсем соответствующие методы, чтобы фактически соответствовать, например, для всех, имеющих одинаковое имя метода.)

+1

Впечатляет! Действительно, это экономит некоторую типизацию, спасибо. –

+0

Из-за отсутствия рабочего ответа на исходный вопрос, я принимаю ваш ответ. –

-1

Одним из способов является использование отражения:

object PojoObservables 

val pojoObservableFact = PojoObservables.getClass.getConstructor() 
pojoObservableFact.setAccessible(true) 
pojoObservableFact.newInstance() 

Теперь мы можем назвать методы PojoObservables.method ...

+0

Это не работает. Во-первых, «PojoObservables» определен в Java, а не в Scala. Во-вторых, вызов 'newInstance()' в Constructor возвращает объект типа 'PojoObservables', но я до сих пор не могу назвать какой-либо из статических методов - это те, которые мне интересны. Вы действительно получили это, чтобы работать? –

+1

Вы, кажется, отвечаете на противоположный вопрос: как получить экземпляр singleton из Scala, загруженный так, как если бы вы были на Java (или как получить вторую копию Scala singleton). –

+0

вы не должны пытаться использовать переменную pojoObservableFact, а скорее объект PojoObservables непосредственно он будет содержать ref для singleton –

0

Так что, ссылка на PojoObservables из here, я могу видеть статический метод observeValue как вы описали.

Это простая задача, Scala рассматривает статические методы на Java-классах, как если бы они были определены на компаньоне. Вы можете использовать это, как будто это старая школу Java:

import org.eclipse.core.databinding.beans.PojoObservables 
... 
val ov = PojoObservables.observeValue(target, property) 

Или вариант новой школы со статическим импортом:

import org.eclipse.core.databinding.beans.PojoObservables._ 
... 
val ov = observeValue(target, property) 

Вы можете пройти любой такой метод вокруг как объект функции , Идея о том, что какой-то функции необходимо сопровождать ее интерфейсом, очень Java-centric thinking, просто ссылайтесь на все, что вам нужно, и поставьте в качестве аргумента для других функций более высокого порядка :)

+0

Спасибо. Конечно, я могу это сделать. Тем не менее, я хочу каким-то образом присвоить «PojoObservables» неявному значению val или передать его как параметр методу, который затем вызывает функцию watchValue, точно так же, как если бы это был объект Singleton «объект» Scala. –

+0

Я должен спросить, но почему? В отсутствие общего интерфейса и других возможных экземпляров, что подразумевает, что вы получаете более или менее простой подстановочный импорт всех методов? –

+1

Я бы использовал структурную типизацию, чтобы «дать» им общий интерфейс. Я хочу, чтобы механизм всегда возвращал «правильный вид» из «IObservable»: как создан с помощью «EMFObservables», если они являются объектами EMF; как созданные с помощью «BeanObservables», если они имеют поддержку изменения свойств; и т.д. –

3

Почему бы просто не пропустить фабричный метод (или набор методов, если необходимо)?

def createObservable(fact: (AnyRef, String) => IObservableValue, 
target: AnyRef, property: String) = fact(target, property) 

createObservable(BeanObservables.createObservable, target, property) 
+0

Хорошая идея.Дело в том, что есть около десятка методов фабрики, которые меня интересуют ... Но это, безусловно, было бы хорошим решением для более простого случая. –