Создавайте динамические классы с зарезервированными словами в качестве переменных

Когда-то этот вопрос был задан без удовлетворительного ответа, кроме «зачем вам это делать» на Зарезервированные слова как имена переменных или методов. Я собираюсь задать этот вопрос еще раз и предоставить контекст, который объясняет, почему это необходимо, и даже направление к правильному решению.

Я пишу код, который динамически создает классы в соответствии со схемой базы данных, которую я не контролирую. По большей части код работает чисто, но примерно в 1% случаев столбцов в Java используются зарезервированные слова в качестве имен столбцов. Следующий код используется для создания динамического поля в классе:

evalClass.addField (CtField.make ("public" + columnType + "" + columnName + ";", evalClass));

Теперь с языком Java это приводит к проблеме, однако в байтовом коде JVM это должно быть совершенно законным, поэтому должен быть способ динамически создавать это поле и обращаться к нему с помощью операций с байтовым кодом. Есть ли у кого-нибудь примеры того, как это будет сделано таким образом, чтобы поддерживать произвольные строки, включая пробелы и зарезервированные слова? Спасибо!


person Erik Brandsberg    schedule 11.09.2016    source источник
comment
На этот вопрос есть абсолютно удовлетворительный ответ: Нет, нет способа. Различие между вашими Вопрос в том, что вы не пытаетесь сделать это на уровне исходного кода. Я предлагаю отредактировать, чтобы переместить эту информацию на передний план, и упомянуть только другой вопрос в конце, говоря, что я видел это, но он спрашивает об исходном коде, и я прошу сделать это на уровне байт-кода, поскольку мы не можем сделать это на уровне исходного кода.   -  person T.J. Crowder    schedule 11.09.2016
comment
Я до сих пор не понимаю, зачем это нужно. Каждая архитектура персистентности, которую я могу придумать, предоставляет простые методы сопоставления имен свойств полей / компонентов с произвольными именами столбцов, и отказ от имен полей ключевых слов Java является одной из причин для этого. Конечно, вы генерируете классы из схемы, но концепция та же. Почему имена полей должны совпадать с именами столбцов? Почему бы вам просто, например, добавить префикс ко всем именам полей (или просто к зарезервированным словам) или что-то вместо этого?   -  person Jason C    schedule 11.09.2016
comment
Даже если бы вы могли генерировать классы, какой цели они бы служили? Вы не могли использовать эти поля ни в одном написанном вами исходном коде. Все это звучит как действительно хороший способ потратить кучу времени. Потратьте это время на создание отображений, упомянутых Джейсоном, в вашу архитектуру персистентности (и / или, возможно, спросите себя, зачем вы пишете свою собственную архитектуру персистентности).   -  person T.J. Crowder    schedule 11.09.2016
comment
@Jason C, проблема в моем случае заключается в том, что SQL, в котором предикаты должны точно отображать структуру данных, И точно отображать имя столбца таблицы, чтобы предотвратить добавление большего количества уровней абстракции (и снижения производительности). Код рассматриваемый действует ниже уровня API JDBC (на самом деле это драйвер JDBC), поэтому существующие механизмы абстракции уже были бы переведены на фактическое имя таблицы на этом этапе.   -  person Erik Brandsberg    schedule 11.09.2016
comment
@ErikBrandsberg Все еще кажется странным ... Я уверен, что у вас есть причина делать то, что вы делаете, но похоже, что вы уже добавляете дополнительный уровень абстракции? Вы создаете эти внутренние сопоставленные классы, но в конечном итоге вы просто собираетесь доставить их обратно в приложение через ResultSet, который предоставляет информацию для каждого столбца как VO, а не для каждой строки как POJO / bean - где они, вероятно, еще раз снова будут сопоставлены с классами на стороне приложения. Но в любом случае достаточно ли просто, например, префикс всех ваших имен полей с _ и убрать его? Плюс ответ Сурьмы.   -  person Jason C    schedule 11.09.2016
comment
(И нет, я не требую, чтобы вы оправдали свои рассуждения, я знаю, что это очень надоедливое требование. Я просто говорю, что мне кажется необычным делать что-то подобное на уровне водителя, возможно, есть и другие подходы к рассмотрению, такие как разрешение любой СУБД, для которой вы пишете драйвер, выполнять больше работы и иметь дело с отправкой / получением необработанных данных напрямую и без отражения).   -  person Jason C    schedule 11.09.2016
comment
@Jason C, подробнее - данные фактически хранятся в Hazelcast, и где запросы из запросов SQL передаются в Hazelcast для запросов для разгрузки базы данных. Таким образом, нам нужны классы, представляющие таблицы (которые мы также не можем контролировать), а предикаты SQL будут обрабатываться вне кеша. Это немного проясняет, а почему переименование полей - не лучший подход?   -  person Erik Brandsberg    schedule 12.09.2016


Ответы (2)


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

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

Обратите внимание, что даже на уровне байт-кода все еще существует несколько ограничений на имена полей. В частности, они не могут быть длиннее 65535 байт в кодировке MUTF8.

person Antimony    schedule 11.09.2016

Вы выбрали единственный способ, где это не работает - API исходного уровня Javassist. Для вас должно быть очевидно, что если вы используете идентификатор для создания исходного кода, идентификатор должен соответствовать правилам исходного кода. Кроме того, использование уже известной предполагаемой структуры для создания исходного кода, который необходимо повторно проанализировать, чтобы восстановить намерение, является наиболее неэффективным способом обработки байтового кода.

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

Тем не менее, вам следует переосмыслить свою предпосылку. Сгенерированные классы, к полям которых можно получить доступ только через Reflection или другой сгенерированный код, не дают никаких преимуществ перед, например, HashMap отображение идентификаторов на значения или массивы, внутренне связывающее столбцы с позициями.

person Holger    schedule 12.09.2016
comment
Спасибо за подтверждение, похоже, Javassist был простым способом получить необходимую функциональность, и в 99,9% случаев он работает. Поскольку эту конкретную функциональность нужно использовать только для настройки классов, производительность не была основным фактором. По идее, этот код представляет собой код уровня драйвера на уровне JDBC, и мы не контролируем поля, а также используем другой код от партнера, который полагается на поля, соответствующие тому, что находится в базе данных. Таким образом, изменение имен полей было бы более болезненным, чем просто выполнение этой работы. - person Erik Brandsberg; 12.09.2016
comment
Что ж, API исходного уровня не только дороже с точки зрения производительности, но и открывает больше возможностей для внесения ошибок. Он не только чувствителен к именам полей, совпадающим с ключевыми словами, но и добавление полей с именами, соответствующими именам типов, может привести к ложному сбою объявлений next. - person Holger; 13.09.2016