Scala SBT: возможная ошибка? - PullRequest
2 голосов
/ 30 августа 2011

Когда я "запускаю sbt" следующий код,

package com.example

import java.io.ObjectInputStream
import java.io.ObjectOutputStream
import java.io.FileInputStream
import java.io.FileOutputStream

object SimpleFailure extends App {
  case class MyClass(a: String, b: Int, c: Double)

  def WriteObjectToFile[A](obj: A, filename: String) {
    val output = new ObjectOutputStream(new FileOutputStream(filename, false))
    output.writeObject(obj)
  }  

  def ReadObjectFromFile[A](filename: String)(implicit m: Manifest[A]): A = {
    val obj = new ObjectInputStream(new FileInputStream(filename)) readObject

    obj match {
      case a if m.erasure.isInstance(a) => a.asInstanceOf[A]
      case _ => { sys.error("Type not what was expected when reading from file") }
    }
  }

  val orig = MyClass("asdf", 42, 2.71)
  val filename = "%s/delete_me.spckl".format(System.getProperty("user.home"))

  WriteObjectToFile(List(orig), filename)

  val loaded = try {
    ReadObjectFromFile[List[MyClass]](filename)
  } catch { case e => e.printStackTrace; throw e }

  println(loaded(0))
}

, я получаю следующее исключение:

java.lang.ClassNotFoundException: com.example.SimpleFailure$MyClass

Однако я могу нормально выполнить код в Eclipse с помощью Scalaплагин.Это ошибка SBT?Интересно, что проблема возникает только при переносе MyClass в List (посмотрите, как «orig» переносится в List в вызове WriteObjectToFile).Если я не включаю в список, все работает нормально.

Ответы [ 3 ]

4 голосов
/ 01 сентября 2011

Поместите это в ваш build.sbt или файл проекта:

fork in run := true
2 голосов
/ 29 августа 2012

Кажется, проблема в загрузчике классов, который используется, когда sbt загружает ваш код. ObjectInputStream описывает его стандартное разрешение загрузчика классов, которое обходит стек. Обычно это заканчивается тем, что мы находим загрузчик, связанный с программой, но в этом случае он использует неправильный.

Мне удалось обойти эту проблему, включив в свой код следующий класс и используя его вместо ObjectInputStream напрямую.

package engine;

import java.io.InputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectStreamClass;

class LocalInputStream extends ObjectInputStream {
    LocalInputStream(InputStream in) throws IOException {
        super(in);
    }

    @Override
    protected Class<?> resolveClass(ObjectStreamClass desc)
        throws ClassNotFoundException
    {
        return Class.forName(desc.getName(), false,
                this.getClass().getClassLoader());
    }
}

Это переопределяет метод resolClass и всегда использует метод, связанный с этим конкретным классом. Пока этот класс является частью вашего приложения, это должно работать.

Кстати, это и быстрее, чем необходимость в форке, но также работает с платформой Play, которая в настоящее время не поддерживает разветвление в режиме разработки.

2 голосов
/ 30 августа 2011

Я тоже смог воспроизвести это, используя sbt 0.10.1 и scalaVersion := "2.9.0-1". Вероятно, вам следует просто сообщить об этом на github или включить в список рассылки.

...