2012년 12월 26일 수요일

Java 와 Scala 코드를 동시에 사용하기

한 프로젝트 또는 모듈에서 다른 언어로 된 코드를 동시에 사용하여 개발하는 작업을 별로 효과적이라고 생각지도 않았고, 그런 경험이 없었다.

생각해보면 C# 과 VB.NET 또는 J# 을 한 프로젝트에서 사용한 적이 있긴한데, 거의 실험용이였고, J# 이 도태되고, C# 이 발전하는 바람에 C# 으로만 개발을 했습니다.

Java 개발을 시작하고, Scala 도 알게되고, Groovy 도 알게 되었지만, 순수 Java 코드로만 개발을 했다.
물론 Scala 는 따로 프로젝트를 만들어서 공부하거나 실험하면서 기존 Java 로 된 라이브러리를 잘 사용했습니다만...
Java 개발 시에 Scala 코드나 라이브러리를 사용할 생각은 잘 못했습니다.

이번에 C# 코드를 Java 로 포팅하면서, Default Parameter 지원같이 코딩량을 줄일 수 있는 Scala 가 필요했는데, Java 와 Scala 코드를 동시에 사용하는 코드 개발 방법을 몰라 포기 했었죠.
몇번 시도 했는데, 상호 교차 참조 시에는 문제가 생기더군요... 쩝...

오늘 제대로 된 정보를 얻어 따라해보니 상호 교차 되어도 문제없이 컴파일과 실행이 되는 군요. ㅎㅎ

우선 Java 와 Scala 를 동시에 사용하여 개발하기는
http://www.codecommit.com/blog/scala/joint-compilation-of-scala-and-java-sources 를 참고하시면 됩니다.

전 maven 으로 개발하므로, maven 코드를 그대로 복사해서 사용했습니다.
그 전에도 비슷하게 만들어져 있었는다. compiler plugin 순서를 scala , java 순으로 해야 하더군요 ㅠ.ㅠ

요렇게 한 다음

ValueObjectBase.java
public abstract class ValueObjectBase implements IValueObject {

 //private static final long serialVersionUID = 5546630455380910528L;

 @Override
 public boolean equals(Object obj) {
  return obj == this ||
          (obj != null &&
            getClass() == obj.getClass() &&
            hashCode() == obj.hashCode());
 }

 @Override
 public int hashCode() {
  return System.identityHashCode(this);
 }

 @Override
 public String toString() {
  return this.buildStringHelper().toString();
 }

 /**
  * {@link ValueObjectBase#toString()}을 재정의하지 말고, buildStringHelper를 재정의 하세요.
  */
 protected Objects.ToStringHelper buildStringHelper() {
  return Objects.toStringHelper(this);
 }
}


TimeVal.scala
class TimeVal extends ValueObjectBase with Comparable[TimeVal] {

 var time: DateTime = _

 def this(duration: Duration) {
  this()
  this.time = new DateTime().withMillisOfDay(duration.getMillis.toInt)
 }

 def this(moment: DateTime) {
  this()
  this.time = new DateTime().withMillis(moment.getMillisOfDay.toLong)
 }

 def this(hourOfDay: Int, minuteOfHour: Int = 0, secondOfMinute: Int = 0, millisOfSecond: Int = 0) {
  this()
  time = new DateTime().withTime(hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond)
 }

 def datetime: DateTime = this.time

 def hourOfDay: Int = time.getHourOfDay

 def minuteOfHour: Int = time.getMinuteOfHour

 def secondOfMinute: Int = time.getSecondOfMinute

 def millisOfSecond: Int = time.getMillisOfSecond

 def millis: Long = time.getMillis

 def getDateTime(moment: DateTime): DateTime = moment.withTimeAtStartOfDay().plus(millis)

 def getDateTime(date: DateVal): DateTime = date.getDateTime(this)

 override def hashCode(): Int = HashTool.compute(time)

 protected override def buildStringHelper() =
  super.buildStringHelper()
   .add("time", time)

 def compareTo(other: TimeVal) = {
  Guard.shouldNotBeNull(other, "other")
  time.compareTo(other.time)
 }
}

object TimeVal {

 def now: TimeVal = new TimeVal(DateTime.now())
}


TimeVal 사용 예

public static DateTime TimePart(DateTime dateTime) {
    return new TimeVal(dateTime).datetime();
}


Scala 언어로 된 TimeVal가 Java 클래스를 상속 받고, Class 를 사용하는 것은 당연하지만, 동시에 Java 코드에서 Scala 클래스와 Object를 사용하게 되었습니다.

이로서 코드량을 확연히 줄이거나, Scala 코드로 구현하는 것이 더 효과적일 때에는 자유스럽게 사용하게 되었습니다.

한손잡이보다 양손잡이가 더 좋겠죠? (물론 코드의 품질의 충분조건은 아닙니다^^)

댓글 없음: