Как я могу создать файл класса динамически? - PullRequest
4 голосов
/ 17 февраля 2009

Я хочу создать файл класса динамически. Вот и все ... С данным ResultSet, извлекая метаданные, я хочу динамически построить файл класса с помощью методов getter и setter для всех столбцов, которые существуют в ResultSet. Также я должен быть в состоянии использовать этот файл класса, сгенерированный, где бы я ни захотел, в моем последующем использовании. Может ли какой-либо орган предложить мне лучший способ реализовать это. Также, если какие-либо существующие jar-файлы доступны для реализации, это было бы полезно.

Ответы [ 8 ]

6 голосов
/ 17 февраля 2009

Возможно Apache Beanutils может удовлетворить ваши требования?

См. Раздел Dynabeans

В частности:

3.3 ResultSetDynaClass (набор результатов Wraps в DynaBeans)

Очень распространенный вариант использования API-интерфейсов DynaBean - обернуть другие коллекции «вещей», которые обычно не представляются как JavaBeans. Одна из наиболее распространенных коллекций, которую было бы неплохо обернуть, - это java.sql.ResultSet, который возвращается, когда вы просите драйвер JDBC выполнить инструкцию SQL SELECT. Commons BeanUtils предлагает стандартный механизм для отображения каждой строки набора результатов как DynaBean, который вы можете использовать, как показано в этом примере:

  Connection conn = ...;
  Statement stmt = conn.createStatement();
  ResultSet rs = stmt.executeQuery
    ("select account_id, name from customers");
  Iterator rows = (new ResultSetDynaClass(rs)).iterator();
  while (rows.hasNext()) {
    DynaBean row = (DynaBean) rows.next();
    System.out.println("Account number is " +
                       row.get("account_id") +
                       " and name is " + row.get("name"));
  }
  rs.close();
  stmt.close();

3.4 RowSetDynaClass (отключенный результат, установленный как DynaBeans)

Хотя ResultSetDynaClass - очень полезный метод для представления результатов запроса SQL в виде серии DynaBeans, важной проблемой является то, что базовый ResultSet должен оставаться открытым в течение периода времени, в течение которого строки обрабатываются вашим приложением. Это препятствует возможности использовать ResultSetDynaClass в качестве средства передачи информации от уровня модели на уровень представления в архитектуре модель-представление-контроллер, такой как предоставляемая Struts Framework, потому что нет простого механизма, гарантирующего, что результирующий набор наконец закрыто (и базовое соединение вернулось в его пул соединений, если вы его используете).

Класс RowSetDynaClass представляет другой подход к этой проблеме. Когда вы создаете такой экземпляр, базовые данные копируются в набор DynaBeans в памяти, которые представляют результат. Преимущество этого метода, конечно, заключается в том, что вы можете немедленно закрыть ResultSet (и соответствующий оператор), как правило, даже прежде чем обрабатывать фактические данные, которые были возвращены. Недостаток, конечно, заключается в том, что вы должны оплачивать затраты на производительность и память при копировании данных результатов, а данные результатов должны полностью помещаться в доступную кучную память. Для многих сред (особенно в веб-приложениях) этот компромисс обычно весьма выгоден.

В качестве дополнительного преимущества класс RowSetDynaClass определен для реализации java.io.Serializable, так что его (и DynaBeans, которые соответствуют каждой строке результата) можно удобно сериализовать и десериализовать (до тех пор, пока базовый столбец) значения также сериализуемы). Таким образом, RowSetDynaClass представляет собой очень удобный способ передачи результатов SQL-запроса в удаленное клиентское приложение на основе Java (такое как апплет).

5 голосов
/ 17 февраля 2009

Дело в том, что, исходя из звуков вашей ситуации, я понимаю, что вы хотите создать этот класс во время выполнения на основе содержимого ResultSet, которое вы только что вернули из запроса к базе данных. Это все хорошо, и может быть сделано с помощью манипулирования байт-кодом.

Однако какую выгоду, по вашему мнению, вы получите от этого? Ваш другой код не сможет вызывать какие-либо методы для этого класса (потому что он не существовал, когда они были скомпилированы), и, следовательно, единственный способ фактически использовать этот сгенерированный класс - это либо с помощью отражения, либо с помощью методов его родительского класса реализованные интерфейсы (я собираюсь предположить, что это расширит ResultSet). Вы можете сделать последнее без переплетения байт-кода (посмотрите на динамические прокси для произвольных реализаций интерфейса во время выполнения), и если вы делаете первое, я не вижу, как иметь класс и механически вызывать getFoo метод с помощью отражения лучше, чем просто вызов resultSet.getString("foo") - он будет медленнее, более громоздким и менее безопасным для типов.

Итак - вы действительно хотите создать класс для достижения своей цели?

4 голосов
/ 17 февраля 2009

Если вы используете Java 6, вы можете написать свой код и напрямую вызвать компилятор Java :

   Files[] files1 = ... ; // input for first compilation task
   Files[] files2 = ... ; // input for second compilation task

   JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
   StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);

   Iterable<? extends JavaFileObject> compilationUnits1 =
       fileManager.getJavaFileObjectsFromFiles(Arrays.asList(files1));
   compiler.getTask(null, fileManager, null, null, null, compilationUnits1).call();

   Iterable<? extends JavaFileObject> compilationUnits2 =
       fileManager.getJavaFileObjects(files2); // use alternative method
   // reuse the same file manager to allow caching of jar files
   compiler.getTask(null, fileManager, null, null, null, compilationUnits2).call();

   fileManager.close();

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

К сожалению, это то, что вы должны делать в Java.

В C # вы просто используете тип 'var'.

4 голосов
/ 17 февраля 2009

Возможно, вы захотите взглянуть на BCEL , хотя я считаю, что есть и другие библиотеки манипулирования байт-кодом.

1 голос
/ 17 февраля 2009

Я сделал что-то похожее. Но я бы не стал создавать динамические классы. У меня был объект под названием Schema, который загружал бы данные каждой нужной мне таблицы. У меня был объект таблицы, который будет иметь тип схемы. Каждый объект схемы имел бы атрибут столбцов, в то время как объект таблицы имел атрибут со значением и ссылкой на атрибут столбца схемы.

В схеме было все необходимое для вставки, выбора, удаления, обновления данных в базе данных.

И у меня был посредник, который обрабатывал бы соединение между базой данных и объектом Table.

   Table t = new Table('Dog');   
   t.randomValue(); // needed for the purpose of my project   
   t.save();    
   Table u = Table.get(t);
   u.delete();

Но он может иметь что-то, чтобы легко получить значение для определенного имени столбца. В любом случае, этот принцип прост, я мог бы загрузить данные, содержащиеся в таблице information_data, и, вероятно, тоже мог бы работать с описанием.

Я смог загрузить любую таблицу динамически, поскольку таблица имела динамические атрибуты, структура не была жестко закодирована. Но нет реальной необходимости создавать новые классы для каждой таблицы.

Было также кое-что, что могло бы быть важно отметить. Каждая схема таблицы была загружена один раз. Таблицы имели ссылку только на схемы, а схемы имели ссылку на столбец. столбец имел ссылки на тип столбца и т.д ...

Было бы интересно найти лучшее применение, чем было. Я сделал это для случая блока на репликации базы данных. У меня не было никакого реального интереса кодировать класс для каждой из 30 таблиц и делать вставку / удаление / обновления и выбор. Это единственная причина, по которой я вижу, что это полезно для создания чего-то динамического в SQL. Если вам не нужно ничего знать о таблицах и вы хотите только вставить / удалить ненужные файлы.

Если бы мне пришлось переделывать свой код, я бы использовал более ассоциативный массив.
В любом случае Гудлак

1 голос
/ 17 февраля 2009

Я запутался в том, как это должно работать. И я не думаю, что это возможно. И вот почему:

Если вы хотите использовать код класса в остальной части вашего приложения, вам нужен интерфейс (или интенсивное использование рефлексии), и это означало бы, что вы заранее знаете типы столбцов, что отрицательно сказывается на назначении сгенерированного класса. 1003 *

Сгенерированный класс может конфликтовать во время выполнения с другим. Если вы создаете новый класс для каждого вызова SQL, у вас будут разные классы для одной и той же цели. И они, вероятно, даже не передадут обычный вызов «равным». Вы должны искать классы из ранее выполненных операторов. И вы теряете гибкость и / или наполняете свою кучу классами.

0 голосов
/ 17 февраля 2009

Я обнаружил, что в JSF бины и карты могут использоваться взаимозаменяемо. Следовательно, для обработки результатов, когда вы не хотите создавать полный набор get / setters, а просто создаете ah: table, гораздо проще создать список с картой для каждой строки, где ключом является имя столбца (или число), а значением является содержимое столбца.

Если вы сочтете это уместным позже, чтобы сделать его более безопасным с точки зрения типов, вы можете затем переделать внутренний код с помощью bean-компонентов и оставить свой JSF-код без изменений.

0 голосов
/ 17 февраля 2009

Я второй комментарии dtsazza и Stroboskop; генерация нового класса во время выполнения, вероятно, не то, что вы хотите делать в этом случае.

Вы на самом деле не дошли до , почему вы хотите это сделать, но похоже, что вы пытаетесь накатить свой собственный объектно-реляционный картограф . Эту проблему гораздо сложнее понять, чем кажется на первый взгляд.

Вместо того, чтобы строить свою собственную систему снизу вверх, вы можете захотеть взглянуть на существующие решения, такие как Hibernate (система высокого уровня, управляет большинством объектов и запросами за вас) или iBatis (немного более низкоуровневый; он обрабатывает сопоставление объектов, но вы все равно можете написать собственный SQL).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...