Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > Сериализация и передача объектов


Автор: Alar 20.7.2005, 11:12
Следующий тестовый пример. Два приложения, одно создает класс и сериализует его в файл, другое читает. Хотелось бы, чтобы второе ничего не знало о реализации интерфейса IFoo и работало только через интерфейс.

Вот тексты:
Приложение №1. В classpath содержит второе приложение для доступа к IFoo
Код

public class Serializator {
  private static class Foo implements IFoo {
    public void doSomething() {
      System.out.println("Hello, world!!!");
    }
  }
  public static void main(String[] args) {
    IFoo foo = new Foo();
    ObjectOutputStream stream;
    try {
      FileOutputStream fileOutputStream;
      fileOutputStream = new FileOutputStream("test.ser");
      stream = new ObjectOutputStream(fileOutputStream);
      stream.writeObject(foo);
      stream.close();
      System.out.println("Object written.");
    } catch (Exception e) {
      e.printStackTrace();
    } 
  }
}


Приложение №2:
IFoo.java:
Код

public interface IFoo extends Serializable {
  void doSomething();
}


Loader.java:
Код

public class Loader {
  public static void main(String[] args) {
    try {
      FileInputStream fileInputStream = new FileInputStream("test.ser");
      ObjectInputStream stream = new ObjectInputStream(fileInputStream);
      IFoo foo = (IFoo) stream.readObject();
      foo.doSomething();
    } catch (Exception e) {
      e.printStackTrace();
    } 
  }
}


При загрузке получаю java.lang.ClassNotFoundException: bla.bla.bla.Serializator$Foo. В-общем-то понятно почему: Loader не может загрузить класс Foo. Но хотелось бы как-нибудь реализовать подобную схему. То есть загрузить объект и работать с ним только через интерфейс, а про класс ничего не знать.
Куда рыть? :-)

Автор: anonymouse 20.7.2005, 11:21
Код

[b]public [/b]static class Foo implements IFoo {

Автор: Alar 20.7.2005, 11:25
anonymouse, нет не в этом дело. Так я уже пробовал (сначала класс Foo был вообще в отдельном файле). Впрочем как "для галочки" попробовал безымянным классом, через абстрактный класс (вместо интерфейса).

Автор: tux 20.7.2005, 11:34
В любом случае класс должен лежать в Class-Path, и при вызове Serializator и при вызове Loader, информация о том какой именно это класс тоже записывается при сериализации. А вот упоминать сам класс в Loader совсем необязательно, достаточно интерфейса.

Автор: anonymouse 20.7.2005, 11:43
У тебя вообше с нормаьлным классом без интерфейса работает ?

Автор: Alar 20.7.2005, 11:55
Цитата(tux @ 20.7.2005, 11:34)
В любом случае класс должен лежать в Class-Path, и при вызове Serializator и при вызове Loader, информация о том какой именно это класс тоже записывается при сериализации.

Это-то понятно. Проблема как раз в том, что небходимо, чтобы класс не лежал в classpath.
Цитата(anonymouse @ 20.7.2005, 11:43)
У тебя вообше с нормаьлным классом без интерфейса работает ?

Работает и с интерфейсом, если класс Foo затолкать в classpath.

Автор: tux 20.7.2005, 12:01
Цитата
Проблема как раз в том, что небходимо, чтобы класс не лежал в classpath.

Так не получится, откуда JVM узнает инфу о классе? При сериализации байт-код не сохраняется. Единственное, что могу предложить - написать свой собственный мудреный класс-лоудер, который будет грузить класс не из Class-Path, а откуда-то из другого места, по ссылке из сети, например.

Автор: Alar 20.7.2005, 12:52
Цитата(tux @ 20.7.2005, 12:01)
написать свой собственный мудреный класс-лоудер,

а как это вообще делается? smile
а можно ли сделать так:
Код

      stream.writeObject(foo.getClass());
      stream.writeObject(foo);


... а другое приложение его считает?

Автор: batigoal 20.7.2005, 13:02
Цитата(Alar @ 20.7.2005, 13:52)
а как это вообще делается? smile

Посмотри тут:
http://java.sun.com/developer/onlineTraining/Security/Fundamentals/magercises/ClassLoader/help.html

Ну и доку:
http://java.sun.com/j2se/1.5.0/docs/api/java/lang/ClassLoader.html


Цитата(Alar @ 20.7.2005, 13:52)
stream.writeObject(foo.getClass());
stream.writeObject(foo);

А потом восстановить его через Class.forName()? Смелая мысль. Может, попробуешь? Интересно...

Автор: Alar 20.7.2005, 13:08
Цитата(Lamer @ 20.7.2005, 13:02)
Может, попробуешь?

Попробовал. Защита от извращенцев работает smile
На попытку загрузить класс:
Код

java.lang.ClassNotFoundException: bla.bla.bla.Serializator$Foo


ЗЫ. за ссылки - спасибо, почитаю.

Автор: tux 20.7.2005, 13:12
Вот здесь я выкладывал пример загрузчика классов:
http://forum.vingrad.ru/index.php?showtopic=53371&hl=
Цитата
А потом восстановить его через Class.forName()? Смелая мысль. Может, попробуешь? Интересно...

Опять-таки ведь в поток запишется состояние объекта, а не байт-код класса. А вот найти в Class-Path нужный класс и записать в поток байт-код можно попробовать. Хотя я себе не представляю задачу, где это нужно. Неужели проще это реализовать, чем передать клиенту jar с нужным классом?

Автор: kashka 20.7.2005, 16:43
Странно а у меня все работает.
Hello, world!!!

Автор: Alar 21.7.2005, 06:30
Цитата(kashka @ 20.7.2005, 16:43)
Hello, world!!!

Hello, kashka!!!
Ты просто не выполнил(а) условия: нужно, чтобы первый проект видел второй (classpath), а второй НЕ видел первый. В этом смысл. Если второму добавить первый в classpath или вообще все спихать в один, то конечно все будет работать.

По теме: похоже простыми способами проблема не решается. smile Придется делать по-другому smile
Спасибо всем ответившим.

Автор: tux 21.7.2005, 08:37
To Alar
В общем идея такая... Пусть сервер - это Serializator, клиент - Loader. Для того, чтобы в клиенте получить класс, которого нет в Class-Path можно реализовать следующее:
на сервере:
  • находим в jar-файлах и каталогах из Class-Path байт-код класса, получаем его как массив байтов. Как это сделать должно быть описано во всех примерах класс-лоудеров;
  • передаем клиенту полученный массив байтов и сериализованный класс через файл, сокет или еще каким-то макаром.
на клиенте:
  • реализуем класс-лоудер (без него к сожалению никуда), который преобразует массив байтов в нужный класс, опять-таки примеры реализации есть, но не для данного случая конечно;
  • получаем байт-код в массиве и сериализованный класс;
  • создаем класс, используя реализованный класс-лоудер.
Кажется должно сработать. Сложнее если в классе есть атрибуты нестандартных классов, тогда надо придумывать и как их передавать. Если будешь это реализовывать, напиши что получилось в результате. Интересно все-таки. smile

Автор: zone51 13.1.2008, 02:14
Кстати вот у меня анаог проблема встала. Есть клиент и есть сервер. Сервер посылает клиенту обьект-мой класс. Причем с заранее установленными полями. И выскакивает такой же эксепшн что не найден класс. Прошу если кто решил эту проблему напишите или посоветуйте еще чтонить. Спасибо. smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)