2015-09-11 6 views
1

Пусть User случай класс, который содержит информацию о пользователе:Scala: сериализуемая альтернатива java.lang.reflect.Field

case class User(name: String, age: Int) 

данного имени поля (например, "name" или "age"), я хочу вернуться a функция, которая извлекает это поле (без разбора имени поля снова). Короче говоря, мне нужно, чтобы это работало:

val u = User(name = "john",age = 44) 
val func = extractFunctionFromFieldName("name") // returns func: User => Any 
func(u) // return "john" 

Читая о рефлексии, я получил что-то вроде этого, чтобы работать:

def extractFunctionFromFieldName(s: String): User => Any = { 
    val f = classOf[User].getDeclaredField(s) 
    f.setAccessible(true) 
    u: User => f.get(u) 
} 

Проблема заключается в том, что эта функция не сериализации, поскольку java.lang.reflect.Field не сериализации.

Любые предложения или альтернативы?

Notes/более фона:

  • Список полей намного больше, чем просто {name,age} и постоянно растет. Вот почему я хочу избежать жесткого кодирования
  • Использование productElement должно работать без проблем с сериализацией, поскольку поля заменяются цифрами. Но я понимаю, что нет никаких гарантий относительно порядка элементов продукта.
  • BTW, мне нужно, чтобы он был сериализуемым, поскольку я использую это с искровой апачей.

ответ

2

Использование продуктаЭлемент должен работать без проблем сериализации, поскольку поля заменяются цифрами. Но я понимаю, что нет никаких гарантий относительно порядка элементов продукта.

Есть. Для класса case они будут в том же порядке, что и параметры.

В качестве альтернативы вы можете создать класс, который все еще может быть функцией (немного больше общего здесь, если это не требуется, изменить для работы с User только должно быть легко):

case class ExtractField[T](s: String)(implicit t: ClassTag[T]) extends (T => Any) { 
    @transient lazy val f = { 
    val f = t.runtimeClass.getDeclaredField(s) 
    f.setAccessible(true) 
    f 
    } 

    def apply(x: T) = f.get(x) 
} 

Это будет инициализировать поле только в первый раз, когда он применяется, и поэтому может применяться много раз после десериализации его один раз без повторения вызовов getDeclaredField.

Первоначально я не заметил, что это уже было задано вопросом, поэтому другое решение, которое я дал первоначально, неприменимо: вы можете просто перемещать f внутри функции (в вашем случае f уже известно, когда вы создаете функцию объект и «захвачен» им, поэтому он должен быть сериализован):

def extractFunctionFromFieldName(s: String): User => Any = { u: User => 
    val f = classOf[User].getDeclaredField(s) 
    f.setAccessible(true) 
    f.get(u) 
} 
+0

Благодарим за ответ. Но, как я сказал в вопросе, я хотел бы, чтобы функция избегала необходимости синтаксического анализа строки, содержащей имя поля, каждый раз при вызове функции. Представьте, что функция генерируется один раз, но применяется в миллиард раз. – Amir

+0

Именно поэтому я дал последнее решение. Он создаст 'f' только в конструкторе, т. Е. В вашем случае при десериализации. –

+0

Вы также должны рассмотреть решение 'productElement', которое вообще не будет включать отражение. –

 Смежные вопросы

  • Нет связанных вопросов^_^