띵유로그

[오류]java.lang.NoSuchMethodError: scala.reflect.internal... spark library 설정 본문

DataEngineering/SPARK

[오류]java.lang.NoSuchMethodError: scala.reflect.internal... spark library 설정

띵유 2022. 1. 12. 13:20
반응형

scala repl에서 

caseclass 를 정의하려고 하니 다음과 같은 에러가 난다.

case class XXXX(변수명1: String, 변수명2: String, is_regex: String)
java.lang.NoSuchMethodError: scala.reflect.internal.Definitions$definitions$.classExistentialType(Lscala/reflect/internal/Symbols$Symbol;)Lscala/reflect/internal/Types$Type;
	at scala.tools.nsc.typechecker.SyntheticMethods$$anonfun$canEqualMethod$1$1.apply(SyntheticMethods.scala:147)
	at scala.tools.nsc.typechecker.SyntheticMethods$$anonfun$canEqualMethod$1$1.apply(SyntheticMethods.scala:146)
	at scala.tools.nsc.typechecker.MethodSynthesis$ClassMethodSynthesis.finishMethod(MethodSynthesis.scala:58)

 

기존에 잘 사용하고 있었는데 다른 프로젝트를 편집하고 다시돌아왔더니 이런 에러가 나는데,,,

 

reflect 라고 로그에 써있어서 reflect 라이브러리를 지우고 다시 실행해보니 정상적으로 실행된다.

 

이번기회에 reflect 라이브러리에대해서 정리하려 한다.

reflection의 역할은 다음과 같이 3가지로 정리할 수 있다.

  • 제네릭 유형을 포함하여 해당 객체의 유형을 검사
  • 새로운 객체를 인스턴스화
  • 해당 객체의 멤버 접근 or 호출

 

1) 제네릭 유형을 포함하여 해당 객체의 유형을 검사

컴파일타임에서는 scala 의 타입은 없다. 즉 스칼라 컴파일러는 컴파일 시간에 런타임 유형을 inspection할 수 없다. 

그러나 reflect 를 통해 컴파일 시간에 미리 런타임에 결정되는 타입이라는 힌트를 줄 수 있다.

scala> import scala.reflect.runtime.{universe => ru}
import scala.reflect.runtime.{universe=>ru}

scala> val l = List(1,2,3)
l: List[Int] = List(1, 2, 3)

scala> def getTypeTag[T: ru.TypeTag](obj: T) = ru.typeTag[T]
getTypeTag: [T](obj: T)(implicit evidence$1: ru.TypeTag[T])ru.TypeTag[T]

scala> val theType = getTypeTag(l).tpe
theType: ru.Type = List[Int]

 

 

다음과 같이 reflect를 import 하면 컴파일 타임에서도 타입에 대해 정의할 수 있다.

1) l 이라는 리스트를 만들었고
2) type을 가져오는 getTypeTag함수를 작성한다. T에 대응할 ru.TypeTag 를 만든다.

3) 이제 l을 파라미터로 사용할 수 있다. |

2) 새로운 객체를 인스턴스화

scala> case class Person(name: String)
defined class Person

scala> val m = ru.runtimeMirror(getClass.getClassLoader)
m: scala.reflect.runtime.universe.Mirror = JavaMirror with ...

case class 를 미리 정의해두고 reflect의 runtimeMirror를 사용하면 아래와 같이 인스턴스를 만들 수 있다.

scala> val classPerson = ru.typeOf[Person].typeSymbol.asClass
classPerson: scala.reflect.runtime.universe.ClassSymbol = class Person

scala> val cm = m.reflectClass(classPerson)
cm: scala.reflect.runtime.universe.ClassMirror = class mirror for Person (bound to null)

3) 런타임 유형의 멤버 엑세스 및 호출 

 

//case class 정의 & 인스턴스 생성
scala> case class Purchase(name: String, orderNumber: Int, var shipped: Boolean)
defined class Purchase

scala> val p = Purchase("Jeff Lebowski", 23819, false)
p: Purchase = Purchase(Jeff Lebowski,23819,false)

//reflect import & 클래스 로더에 의해 로드된 모든 클래스와 유형 사용하도록  mirror 가져옴
scala> import scala.reflect.runtime.{universe => ru}
import scala.reflect.runtime.{universe=>ru}

scala> val m = ru.runtimeMirror(p.getClass.getClassLoader)
m: scala.reflect.runtime.universe.Mirror = JavaMirror with ...

//필더 선언 찾기
scala> val shippingTermSymb = ru.typeOf[Purchase].decl(ru.TermName("shipped")).asTerm
shippingTermSymb: scala.reflect.runtime.universe.TermSymbol = method shipped

// p의 미러인 im 생성 (멤버에 액세스하려면 미러가 필요함)
scala> val im = m.reflect(p)
im: scala.reflect.runtime.universe.InstanceMirror = instance mirror for Purchase(Jeff Lebowski,23819,false)

scala> val shippingFieldMirror = im.reflectField(shippingTermSymb)
shippingFieldMirror: scala.reflect.runtime.universe.FieldMirror = field mirror for Purchase.shipped (bound to Purchase(Jeff Lebowski,23819,false))

//멤버변수 변경
scala> shippingFieldMirror.get
res7: Any = false

scala> shippingFieldMirror.set(true)

scala> shippingFieldMirror.get
res9: Any = true

 

반응형

'DataEngineering > SPARK' 카테고리의 다른 글

[SPARK] 스파크 튜닝 방안  (0) 2022.03.21
[SPARK] 스파크 기본 아키텍쳐  (0) 2022.03.03
[SPAKR] note  (0) 2021.11.04
[SPARK] SPARK 지연연산의 이점  (0) 2021.08.18
[스파크] RDD - Double RDD 전용 함수  (0) 2021.03.08
Comments