вопрос по reflection
От: aios  
Дата: 07.11.18 06:14
Оценка:
допустим есть декларация

string str = "public class c { // описание методов и свойств}";


требуется создать экземпляр этого класса и использовать его. на дот.нете такое делается нараз, а погуглил насчет джавы — приходится извращаться:
1) создать файл куда поместить данную строку;
2) вызвать компилятор
3) загрузить класс через ClassLoader
и только уже потом инстансировать и использовать.
без манипуляций с дисковыми операциями никак не обойтись? может все же возможно также как в шарпе?
Re: вопрос по reflection
От: vsb Казахстан  
Дата: 07.11.18 08:08
Оценка: 5 (2)
Вариант 1 (для выражений):

        var jShell = JShell.create();
        jShell.eval("String k1, k2;");
        jShell.eval("k1 = \"test\"; k2 = \"tset\";");
        var k1 = jShell.variables().filter(v -> v.name().equals("k1")).findAny().get();
        System.out.println(jShell.varValue(k1));


Вариант 2 (требует org.patrodyne:patrodyne-scripting-java:1.0.0):

        var scriptEngineManager = new ScriptEngineManager();
        var scriptEngine = scriptEngineManager.getEngineByName("Java");
        var evalString = "k1 = \"test\"; k2 = \"tset\";";
        var evalClass = (Class<?>) scriptEngine.eval("" +
                "class Example {" +
                "    String k1, k2;" +
                "    Example() {" +
                "    }" +
                "    void run() {" +
                "        " + evalString + "" +
                "    }" +
                "}");
        var evalCtor = evalClass.getDeclaredConstructor();
        evalCtor.setAccessible(true);
        var evalObj = evalCtor.newInstance();
        Method evalRunMethod = evalClass.getDeclaredMethod("run");
        evalRunMethod.setAccessible(true);
        evalRunMethod.invoke(evalObj);
        Field evalK1Field = evalClass.getDeclaredField("k1");
        evalK1Field.setAccessible(true);
        var k1 = evalK1Field.get(evalObj);
        System.out.println(k1);


Вариант 3 (то, что ты описал, но без работы с диском, требует com.google.jimfs:jimfs:1.1):


        var javaCompiler = ToolProvider.getSystemJavaCompiler();
        var fileManager = javaCompiler.getStandardFileManager(null, ENGLISH, UTF_8);
        var fileSystem = Jimfs.newFileSystem(Configuration.unix());
        var evalString = "k1 = \"test\"; k2 = \"tset\";";
        Files.writeString(fileSystem.getPath("/Example.java"), "" +
                "public class Example implements Runnable {" +
                "    public String k1, k2;" +
                "    public void run() {" +
                "        " + evalString + "" +
                "    }" +
                "}");
        var sources = fileManager.getJavaFileObjects(fileSystem.getPath("/Example.java"));
        javaCompiler.getTask(null, fileManager, null, null, null, sources).call();
        var bytecode = Files.readAllBytes(fileSystem.getPath("/Example.class"));
        var classLoader = new ClassLoader() {
            @Override
            protected Class<?> findClass(String name) throws ClassNotFoundException {
                if (name.equals("Example")) {
                    return defineClass(name, bytecode, 0, bytecode.length);
                }
                return super.findClass(name);
            }
        };
        var exampleClass = classLoader.findClass("Example");
        var exampleObj = (Runnable) exampleClass.getConstructor().newInstance();
        exampleObj.run();
        System.out.println(exampleClass.getField("k1").get(exampleObj));


Эти примеры из этой темы.
Отредактировано 07.11.2018 8:10 vsb . Предыдущая версия . Еще …
Отредактировано 07.11.2018 8:09 vsb . Предыдущая версия .
Re: вопрос по reflection
От: StanislavK Великобритания  
Дата: 07.11.18 09:39
Оценка:
Здравствуйте, aios, Вы писали:

A>без манипуляций с дисковыми операциями никак не обойтись? может все же возможно также как в шарпе?

Без библиотек пока никак.

Можно попробовать вот это:
https://github.com/OpenHFT/Java-Runtime-Compiler
Re[2]: вопрос по reflection
От: aios  
Дата: 07.11.18 12:33
Оценка:
vsb>Вариант 2 (требует org.patrodyne:patrodyne-scripting-java:1.0.0):

vsb>
vsb>        var scriptEngineManager = new ScriptEngineManager();
vsb>        var scriptEngine = scriptEngineManager.getEngineByName("Java");
vsb>        var evalString = "k1 = \"test\"; k2 = \"tset\";";
vsb>        var evalClass = (Class<?>) scriptEngine.eval("" +
vsb>                "class Example {" +
vsb>                "    String k1, k2;" +
vsb>                "    Example() {" +
vsb>                "    }" +
vsb>                "    void run() {" +
vsb>                "        " + evalString + "" +
vsb>                "    }" +
vsb>                "}");
 vsb>        var evalCtor = evalClass.getDeclaredConstructor();
vsb>        evalCtor.setAccessible(true);
vsb>        var evalObj = evalCtor.newInstance();
vsb>        Method evalRunMethod = evalClass.getDeclaredMethod("run");
vsb>        evalRunMethod.setAccessible(true);
vsb>        evalRunMethod.invoke(evalObj);
vsb>        Field evalK1Field = evalClass.getDeclaredField("k1");
vsb>        evalK1Field.setAccessible(true);
vsb>        var k1 = evalK1Field.get(evalObj);
vsb>        System.out.println(k1);
vsb>


а этот на выделенном фрагменте падает:

java.lang.NullPointerException
at org.patrodyne.scripting.java.JavaCompiler.getStandardFileManager(JavaCompiler.java:61)
at org.patrodyne.scripting.java.JavaCompiler.compile(JavaCompiler.java:124)
at org.patrodyne.scripting.java.JavaCodeScriptEngine.parse(JavaCodeScriptEngine.java:161)
at org.patrodyne.scripting.java.JavaCodeScriptEngine.eval(JavaCodeScriptEngine.java:126)
at javax.script.AbstractScriptEngine.eval(Unknown Source)
at org.jxls.demo.reader.XlsReaderDemo.Test(XlsReaderDemo.java:60)
at org.jxls.demo.reader.XlsReaderDemo.main(XlsReaderDemo.java:49)


может тоже не предназначено для восьмой джавы?

vsb>Вариант 3 (то, что ты описал, но без работы с диском, требует com.google.jimfs:jimfs:1.1):


че-то не смог библиотеку подключить. может она только для 10й Java?

vsb>Эти примеры из этой темы.
Re[3]: вопрос по reflection
От: vsb Казахстан  
Дата: 07.11.18 14:24
Оценка: 2 (1)
Здравствуйте, aios, Вы писали:

A>а этот на выделенном фрагменте падает:


Надо запускать через JDK, в JRE нет поддержки Java Compiler API.

vsb>>Вариант 3 (то, что ты описал, но без работы с диском, требует com.google.jimfs:jimfs:1.1):


A>че-то не смог библиотеку подключить. может она только для 10й Java?


Нет, она 7+. Скорей всего то же самое, надо запускать через JDK.
Re: вопрос по reflection
От: bzig  
Дата: 07.11.18 15:49
Оценка:
A>требуется создать экземпляр этого класса и использовать его. на дот.нете такое делается нараз, а погуглил насчет джавы — приходится извращаться:


А что за исходная задача? А то может выяснится, что в Яве исходная задача решается проще.
Re[2]: вопрос по reflection
От: aios  
Дата: 07.11.18 16:38
Оценка:
B>А что за исходная задача? А то может выяснится, что в Яве исходная задача решается проще.

кстати да. лучше рассказать, а то может и правда фигней хочу страдать.
в общем один чел на одном крупном авиамоторостроительном предприятии в течение примерно 15 лет или около того писал что-то а-ля 1с планировал (правда у 1с архитектура совсем иная — одна сущность — одна таблица, здесь же реалиационная модель (если можно так выразиться) реализуется логически, на базе ряда таблиц. т.е. куча бизнес объектов, куча бизнес процессов все это упаковано в несколько таблиц грубо говоря. на шарепойнте вроде что-то подобное (очень мало с ним знаком, но он в отличие от этой системы работает и вроде бы даже местами неплохо). самое смешное все данные хранятся в текстовом виде, разделение типов тоже логическое. додумались на эту систему посадить производство. а это несколько тысяч записей в сутки. сначала все шло просто прекрасно. быстро. посадил теток из отдела эксплуатации клепать новые бизнес процессы и благополучно свинтил. веб-часть кстати реализована на викетах. помнишь что это такое? )))) вот такое подкинули мне. когда количество данных перевалило за миллионы записей пользователи начали задумываться. а какого вот хрена интересно у них документ открывается в течение полуминуты, когда погода располагает, а так — 1.5 — 2. ну и понеслась (это еще до моего прихода). надо оптимизировать. а чего там вообще можно соптимизировать, кроме как на корню переписать все нахрен пока еще не совсем полная жопа. что можно оптимизировать при такой архитектуре. когда изучал систему, видел там некоторые осторожные костыли (ну типа ID бизнес объекта стали хранить не в логическом текстовом поле, а физическое приалтерили и проиндексировали — поржал, но пользователи не хотят искать сволочи по айдишнику, они хотят почему захотят все атрибуты в физический слой не переведешь — уже не "1с" получится а вообще непонятный монстр.) ну это так преамбула.
по конкретной задаче. хотят на производстве отчет выгружать за год, а получается за 10 дней например. либо таймаут оракловый, либо 65536 строк в эксел (причем по непонятной мне причине они в poi (библиотека для эксел) использовали даже не xls, а xlt формат. для всех оставшихся в отделе это тайна покрытая мраком зачем.
ну в общем подключил новую версию poi. перевел на xlsx. ограничений теперь можно сказать. но оракловые таймауты иногда правда, но начальство сказала — эт фигня. главное чтобы эксел работал. тем более в новой версии ввели набор классов для быстрой работы с xlsx. на память уже не помню cxssf* вроде. зашибись. скорости достаточные. но блин встрял на том, что многих классов используемых в коде (а переписывать зачисто не хочу — сделать и забыть как страшный сон) нету. в частности для работы со шрифтами. я даже вникать не стал. но самое хреновое, что при существующем функционале, необходимо писать данные не только аппендом, но и править сверху очень активно. и так просто в это не вписаться.
в итоге взгляд остановился на надстройке над poi http://jxls.sourceforge.net/ решил, что использование шаблонов с ней будет самое оно с наименьшими трудозатратами.
теперь зачем хочу reflection. в этой библиотеке понравилось, что задаешь шаблон в экселе, рисуешь как тебе надо, описываешь по класс.поле что куда пихать в какие блоки и вуаля. причем работает очень быстро.
в коде надо описать класс, ну как в их примере, например:

public class Person {
    String name;

    геттеры-сеттеры
}

public class Department {
    String name;
    List<Person> person;

    геттеры-сеттеры
}


потом проинстансировав объект скажем департмент, заполнив его данными, и натравив эту библиотеку на него, она сделает все за тебя, типа где какие персон работают например.

в той системе может быть потенциально (хоть и не используется) любая вложенность подчиненности или просто последовательных блоков. причем достаются они через огромную задницу, что естественно в данном случае.
вот и мне хочется организовать класс такой структуры, чтобы скормить его этой библиотеке. при этом не пришлось бы все переписывать на корню. может подскажете более простое решение.
Re[3]: вопрос по reflection
От: bzig  
Дата: 07.11.18 17:42
Оценка:
Вместо генерирования бинов, можно просто подложить мэпы значений (dictionary в .net)

Если jxls тупой и не сможет брать значения в виде "person.name", то писать "person.get('name')". Хотя мне опять же кажется, что мэпы он должен из коробки поддерживать
Re[4]: вопрос по reflection
От: aios  
Дата: 07.11.18 17:57
Оценка:
Здравствуйте, bzig, Вы писали:

B>Вместо генерирования бинов, можно просто подложить мэпы значений (dictionary в .net)


B>Если jxls тупой и не сможет брать значения в виде "person.name", то писать "person.get('name')". Хотя мне опять же кажется, что мэпы он должен из коробки поддерживать


так он примерно так и делает http://jxls.sourceforge.net/getting_started.html (на скрине сразу поймешь — читать даже не надо). только толку-то? я заранее не знаю какой отчет они (тетки, которые отчетами занимаются на уровне пользователя) замутят, состав колонок и иерархию. поэтому заранее не подготовишь.
Re[4]: вопрос по reflection
От: bzig  
Дата: 07.11.18 17:58
Оценка:
Здравствуйте, bzig, Вы писали:

B>Вместо генерирования бинов, можно просто подложить мэпы значений (dictionary в .net)


B>Если jxls тупой и не сможет брать значения в виде "person.name", то писать "person.get('name')". Хотя мне опять же кажется, что мэпы он должен из коробки поддерживать


Хотя он JEXL использает, а тот из мэпа не позволяет доставить через ".key" http://commons.apache.org/proper/commons-jexl/reference/syntax.html
Нужно писать "map['key']" или в твоём случае "person['name']"
Re[5]: вопрос по reflection
От: bzig  
Дата: 07.11.18 18:02
Оценка:
A>так он примерно так и делает http://jxls.sourceforge.net/getting_started.html (на скрине сразу поймешь — читать даже не надо). только толку-то? я заранее не знаю какой отчет они (тетки, которые отчетами занимаются на уровне пользователя) замутят, состав колонок и иерархию. поэтому заранее не подготовишь.

???

Вместо генерации классов, генерируй мэпы (А то может они у тебя вообще уже сгенерированы, веди как-то ты данные из БД достаёшь).
Re[5]: вопрос по reflection
От: GarryIV  
Дата: 07.11.18 19:20
Оценка: 1 (1) +1
Здравствуйте, bzig, Вы писали:

B>>Если jxls тупой и не сможет брать значения в виде "person.name", то писать "person.get('name')". Хотя мне опять же кажется, что мэпы он должен из коробки поддерживать


B>Хотя он JEXL использает, а тот из мэпа не позволяет доставить через ".key" http://commons.apache.org/proper/commons-jexl/reference/syntax.html

B>Нужно писать "map['key']" или в твоём случае "person['name']"

Там можно и другой движок для выражений прикрутить. Спринговый может через точку.
WBR, Igor Evgrafov
Re[4]: вопрос по reflection
От: aios  
Дата: 08.11.18 07:48
Оценка:
Здравствуйте, vsb, Вы писали:

vsb>Здравствуйте, aios, Вы писали:


A>>а этот на выделенном фрагменте падает:


vsb>Надо запускать через JDK, в JRE нет поддержки Java Compiler API.


действительно помогло. теперь другая проблема. public класс по ходу таким способом (под пунктом 2) не создашь? я попробовал — ругнулся, что файл должен быть для паблика.
Re[5]: вопрос по reflection
От: vsb Казахстан  
Дата: 08.11.18 08:32
Оценка:
Здравствуйте, aios, Вы писали:

A>Здравствуйте, vsb, Вы писали:


vsb>>Здравствуйте, aios, Вы писали:


A>>>а этот на выделенном фрагменте падает:


vsb>>Надо запускать через JDK, в JRE нет поддержки Java Compiler API.


A>действительно помогло. теперь другая проблема. public класс по ходу таким способом (под пунктом 2) не создашь? я попробовал — ругнулся, что файл должен быть для паблика.


Не скажу, не копался подробно. Может быть что-то настроить надо.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.