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 코드로 구현하는 것이 더 효과적일 때에는 자유스럽게 사용하게 되었습니다.

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

2012년 12월 25일 화요일

LambdaJ 소개

.NET LINQ 처럼 Lambda 표현식으로 데이터리 처리하는 방법을 제공해는 라이브러리입니다.
Closure 라는 함수형 언어도 있지만, Java 만을 고집하시는 분들이라면, 아주 괜찮은 라이브러리라 할 수 있습니다.

특히 컬렉션에 대한 Filtering, Sorting, Aggregation 등을 loop 로 표현하게 되면 상당히 코딩량이 많아지는데, 이를 LambdaJ 를 이용하여 엄청나게 줄일 수 있다는 것이 장점이라고 볼 수 있습니다.

아쉽게도 LINQ 도 마찮가지지만, 성능은 당연히 기존 컴파일 방식보다는 평균 3배가량 느립니다.
요렇게 성능이 느린 것을 극복하기 위해 LINQ는 병렬방식으로 처리할 수 있는 길을 열어 놨는데, LambdaJ 는 아쉽게도 이게 없네요... 병렬 처리가 가능하다면 3배 느린 건 멀티코어로 극복이 가능하거든요^^

Java 8 에서 지원할지, LambdaJ 도 지원할지, 아니면 또 다른 Library 가 있는지는 모르지만...
제가 지금까지 조사한 바로는 없네요. 혹시 아시는 분은 코멘트 부탁 드립니다.

다음은 LambdaJ 에 대한 소개 슬라이드이니 이 것을 보시고 공부해 보시기 바랍니다.




제가 .NET 에서도 LINQ 를 헤비하게 사용하였고, Java 개발에도 LINQ 와 유사한 것을 찾고, 헤비하게 사용하려고 하느냐 하면, Data 관련 여러 작업들을 RDBMS의 SQL문장이 아닌 Object Graph 상에서 수행하기 위해서는 단순한 코드로 표현되는 방법이 필요했구요. 그래야만 ORM인 Hibernate 를 사용하는 효과를 극대화 할 수 있기 때문입니다.

결론적으로 RDBMS에서 데이터 연산과 관련된 부분 중에 대용량이 아닌 경우는 Hibernate 에 의한 Domain Model  로부터 쉽게 도출할 수 있는 방법이 지원된다면,  RDBMS 의존도를 더욱 줄일 수 있기 때문입니다.

Java 8 이 나온다 하더라도, 실제 적용되기까지는 시일이 걸리므로, 우선은 LambdaJ 같은 LINQ   와 유사한 기능을 지원하는 라이브러리를 써야 할 것 같네요.

그럼 Java 8 이나 그 후로는?


2012년 12월 23일 일요일

Friends of Guava


원본 : http://code.google.com/p/guava-libraries/wiki/FriendsOfGuava

Friends of Guava

  • Caliper - we use it to benchmark our code
  • Glazed Lists - observable collections
  • GSON - read and write JSON
  • Guice - a mature dependency injector
  • Dagger - a high-performance dependency injector.
  • Google Web Toolkit - we support it
  • ICU4J - unless all your users live in the same place
  • Joda-Time - do not use JDK date/time libraries!
  • JUNG - graphs done right
  • MOE - this is how we keep our internal and external codebases in sync
  • ProGuard - shrinker/bundler/obfuscator/optimizer
  • Mockito - Googlers' favorite mocking framework

Guava 14.0 rc-1 이 나와서 살펴보다가 이 페이지를 발견했네요^^
흠 Glazed List 는 써야할 것 같고, Spring Core 를 써서 굳이 Guice나 Dagger는 쓸 필요가 없을 듯하고 (개인적으로는)
Caliper는 관심가져봐야 겠네요^^