LINUX.ORG.RU

Опыт объединения Java, JavaScript, Python и Ruby с использованием GraalVM

 graalvm, , , ,


0

4

В ноябре этого года вышел более-менее стабильный LTS-релиз GraalVM 20.3.0 от Oracle и я решил с ним поэкспериментировать. Для тех кто не в курсе, GraalVM позволяет использовать в едином окружении различные популярные языки программирования и обеспечивает их разностороннее взаимодействие в рамках некоторой общей среды выполнения. Платформа GraalVM вместе с исполняемой программой на смеси самых разных языков может быть представлена в виде автономного и самодостаточного исполняемого файла, либо работать поверх OpenJDK, Node.js или даже внутри Oracle Database. Наглядная схема из официальной документации:

https://www.graalvm.org/docs/img/graalvm_architecture.png

Поддержка гостевых языков осуществляется с помощью фреймворка Truffle, на основе этой библиотеки можно даже реализовать собственный язык программирования, который получит все плюшки платформы, вроде JIT-компиляции, многостороннего взаимодействия и прочего полезного. Из коробки в дистрибутиве GraalVM сразу присутствует возможность использования:

  • Java, Kotlin, Scala и других языков JVM-платформы.
  • JavaScript вкупе с Node.js и сопутствующим инструментарием.
  • C, C++, Rust и других языков, которые могут быть скомпилированы в LLVM bitcode.

Экспериментальная поддержка заявлена для Python, Ruby, R и WebAssembly.

Собственно, хватит лирики, вот простенький прототип, использующий из экосистем JavaScript, Python и Ruby батарейки, реализующие server-side подсветку синтаксиса фрагментов исходного кода. Подобные библиотеки с богатым охватом языков программирования, которые они могут подсвечивать, отсутствуют на JVM-платформе:

// Highlighter.java, no comments, no checks.
// $ javac Highlighter.java
// $ jar -cvfe highlighter.jar Highlighter *.class
// $ cat hello.py | java -jar highlighter.jar rouge python
import org.graalvm.polyglot.Context;

import java.io.File;
import java.io.FileNotFoundException;

import java.util.Scanner;

public class Highlighter {
  private abstract class Highlight {
    protected final Context polyglot =
      Context.newBuilder("js", "python", "ruby").allowAllAccess(true).allowIO(true)
        .build();

    protected abstract String language();
    protected abstract String renderHtml(String language, String rawCode);

    protected String execute(String sourceCode) {
      try {
        return polyglot.eval(language(), sourceCode).asString();
      } catch (RuntimeException re) { re.printStackTrace(); }
      return sourceCode;
    }

    protected void importValue(String name, String value) {
      try {
        polyglot.getBindings(language()).putMember(name, value);
      } catch (RuntimeException re) { re.printStackTrace(); }
    }
  }

  private class Hjs extends Highlight {
    @Override
    protected String language() { return "js"; }

    @Override
    public String renderHtml(String language, String rawCode) {
      importValue("source", rawCode);

      String hjs = "";
      try {
        hjs = new Scanner(new File("highlight.min.js")).useDelimiter("\\A").next();
      } catch (FileNotFoundException fnfe) { fnfe.printStackTrace(); }

      final String renderLanguageSnippet =
        hjs + "\n" +
        "hljs.highlight('" + language + "', String(source)).value";
      return execute(renderLanguageSnippet);
    }
  }

  private class Rouge extends Highlight {
    @Override
    protected String language() { return "ruby"; }

    @Override
    public String renderHtml(String language, String rawCode) {
      importValue("$source", rawCode);
      final String renderLanguageSnippet =
        "require 'rouge'" + "\n" +

        "formatter = Rouge::Formatters::HTML.new" + "\n" +
        "lexer = Rouge::Lexer::find('" + language + "')" + "\n" +
        "formatter.format(lexer.lex($source.to_str))";
      return execute(renderLanguageSnippet);
    }
  }

  private class Pygments extends Highlight {
    @Override
    protected String language() { return "python"; }

    @Override
    public String renderHtml(String language, String rawCode) {
      importValue("source", rawCode);
      final String renderLanguageSnippet =
        "import site" + "\n" +
        "from pygments import highlight" + "\n" +
        "from pygments.lexers import get_lexer_by_name" + "\n" +
        "from pygments.formatters import HtmlFormatter" + "\n" +

        "formatter = HtmlFormatter(nowrap=True)" + "\n" +
        "lexer = get_lexer_by_name('" + language + "')" + "\n" +
        "highlight(source, lexer, formatter)";
      return execute(renderLanguageSnippet);
    }
  }

  public String highlight(String library, String language, String code) {
    switch (library) {
      default:
      case "hjs": return new Hjs().renderHtml(language, code);
      case "rouge": return new Rouge().renderHtml(language, code);
      case "pygments": return new Pygments().renderHtml(language, code);
    }
  }

  public static void main(String[] args) {
    Scanner scanner = new Scanner(System.in).useDelimiter("\\A");
    if (scanner.hasNext()) {
      String code = scanner.next();
      if (!code.isEmpty()) {
        System.out.println(new Highlighter().highlight(args[0], args[1], code));
      }
    }
  }
}

Как видно, тут смешаны сразу четыре разных языка программирования. Утилита принимает на вход stdin в виде текста исходного файла, передаваемые аргументы определяют используемую библиотеку для подсветки и язык фрагмента, затем подсвечивается код и выводится готовый HTML на stdout терминала.

Подсветка фрагментов кода на стороне сервера лишь простейший пример использования библиотек, которые недоступны для определённой платформы, но доступны на нескольких других. С тем же успехом можно рассматривать какую-нибудь гораздо более полезную научную батарейку, написанную на Python или R, что-нибудь из ML и т. д. Получается, что JVM-платформу со своей кучей библиотек мы можем обогатить батарейками из экосистем других языков программирования и использовать их эксклюзивные библиотеки, альтернативы которых просто недоступны на нашей платформе.

Рецепт установки GraalVM, поддержки языков и библиотек, компиляция и запуск прототипа:

curl -LOJ https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-20.3.0/graalvm-ce-java8-linux-amd64-20.3.0.tar.gz
# curl -LOJ https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-20.3.0/graalvm-ce-java11-linux-amd64-20.3.0.tar.gz
cd /opt/
sudo mkdir graalvm
sudo chown `whoami`:`whoami` graalvm
cd /opt/graalvm/
tar -xvzf ~/graalvm-ce-java8-linux-amd64-20.3.0.tar.gz
rm ~/graalvm-ce-java8-linux-amd64-20.3.0.tar.gz

export GRAALVM_HOME=/opt/graalvm/graalvm-ce-java8-20.3.0
export JAVA_HOME=$GRAALVM_HOME
export PATH=$GRAALVM_HOME/bin:$PATH

gu install python
gu install ruby
# /opt/graalvm/graalvm-ce-java8-20.3.0/jre/languages/ruby/lib/truffle/post_install_hook.sh

graalpython -m ginstall install setuptools
curl -LOJ https://github.com/pygments/pygments/archive/2.7.3.tar.gz
tar -xvzf pygments-2.7.3.tar.gz
cd pygments-2.7.3/
graalpython setup.py install --user
cd ..
rm -Rf pygments-2.7.3/ pygments-2.7.3.tar.gz

gem install rouge

curl -LOJ https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.4.1/highlight.min.js

javac Highlighter.java
jar -cvfe highlighter.jar Highlighter *.class

cat hello.py
#!/usr/bin/env python
print("Hello, World!")

cat hello.py | java -jar highlighter.jar hjs python
<span class="hljs-comment">#!/usr/bin/env python</span>
print(<span class="hljs-string">"Hello, World!"</span>)

cat hello.py | java -jar highlighter.jar rouge python
<span class="c1">#!/usr/bin/env python
</span><span class="k">print</span><span class="p">(</span><span class="s">"Hello, World!"</span><span class="p">)</span>

cat hello.py | java -jar highlighter.jar pygments python
<span class="ch">#!/usr/bin/env python</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Hello, World!"</span><span class="p">)</span>

Благодаря поддержке AOT-компиляции в GraalVM можно даже собрать автономный нативный исполняемый файл из JAR-пакета:

sudo yum install gcc glibc-devel zlib-devel libstdc++-static

gu install native-image
# gu rebuild-images polyglot libpolyglot

native-image --language:js -jar highlighter.jar

cat Highlighter.java | ./highlighter hjs java

Вместо Java VM там будет использована легковесная и низкоуровневая Substrate VM, но с преимуществами JIT-компилятора в случае AOT придётся попрощаться. Зато запуск просто молниеносный, как у всех нативных программ. Стоит отметить, что пока у меня удалось сформировать подобный исполняемый файл лишь для связки JavaScript + Java. Создание подобных нативных образов довольно продолжительная и ресурсоёмкая операция, особенно по памяти. Для сборки примера потребовалось где-то 6 GB RAM, а в более сложных случаях требуется и целых 20 GB RAM.

Прототип постепенно оброс разной функциональностью и благодаря фреймворку Spring, который вполне себе работает на платформе GraalVM, превратился в простенький pastebin-сайт на котором можно обмениваться фрагментами исходного кода.

Все исходники и рецепты я выложил на GitHub: https://github.com/EXL/CodePolyglot
На Хабре имеется скучная и длинная статья про мои изыскания, может кому-нибудь будет интересно её почитать: https://habr.com/ru/post/534044/
Потыкать палочкой прототип в виде сайтика на GraalVM и Spring Boot можно тут: https://code.exlmoto.ru/
Примечание: не факт, что я долго буду держать сайт в онлайне, так что не рассчитывайте сохранять там что-то ценное.

Мне интересно ближайшее будущее GraalVM, похоже Oracle настроен очень серьёзно. Пока проект позиционируется им как альтернативная и идеальная платформа для микросервисов, но уже сейчас его разработка имеет влияние и на классический OpenJDK, например, в релизе JDK 15 была дропнута поддержка JavaScript-движка Nashorn, а в качестве его замены Oracle предлагает попробовать именно GraalVM. Кто знает, вдруг GraalVM в будущем будет предлагаться в качестве рекомендуемой JVM-платформы по умолчанию вместо OpenJDK? Время нам покажет.

Предлагаю обсудить эту грандиозную затею Oracle, пригодится ли кому-нибудь использовать все эти фичи GraalVM на практике? На официальном сайте платформы есть интересное заявление о том, что наша отечественная социальная сеть «Одноклассники» уже использует GraalVM в продакшене для server-side рендеринга React.js, что позволяет добиться хорошей отзывчивости на медленных интернет соединениях.

P.S. Поздравляю с наступающим Новым Годом анонимных и зарегестрированных пользователей ЛОРа. Счастья и крепкого сибирского здоровья вам, ребята!

★★★★★

Последнее исправление: EXL (всего исправлений: 4)

Ответ на: комментарий от Partisan

веб-скрипты в платформе Alfresco

а их реально надо на сервере выполнять да еще и в одной ВМ с серверной частью?

Еслм на JavaScript , то не надо перезагружать приложение при их изменении.

ну ты же понимаешь что необходимость перезагрузки приложения или VM не зависит от языка, который она исполняет, а зависит только от ленивости или криворукости создателя программы?
тем более что в jvm, насколько помню есть инъекции во время исполнения т.е. можно даже не перезапускать исполняемый кусок кода, не то что всё приложение (но это не точно - я не пользовался)

функции в генераторах отчётов.

прям есть выигрыш от выполнения жс на сервере в одной жвм с бэкендом, вместо выполнения того-же но написанного на жаве?

можно пример всё-же? я реально не догоняю

шаги выполнения процессов в process engine-ах (например Activiti) и ETL (например, Pentaho).

поподробнее ибо аналогично не понятно в чём профит от жс вместо явы

rukez ★★★★
()
Ответ на: комментарий от drsm

не доводилось… мощно, как Титаник… :)

об том и разговор - в обычной жвм давно есть всё, что нужно человеку для решения большинства реальных задач, изобретания велосипедов преследуют исключительно пустопорожнюю цель втыкания чего-нить куда-нить - а лучше бы бабу завели (с)

просто компилятор и так есть в jdk изначально - ничто не мешает его выполнить при нужде
в 9ке это перевели из разряда «странных но прикольных костылей» в разряд «фановая штука», но по сути реальной пользы, кроме возможности пихать пользовательские скрипты в приложения (я по этому и среагировал на предложение пихать туда жс) я пока не замечал (в режиме запуска в одной ВМ)

а вот в режиме соло я гоняю иногда жшел - например к нему можно подключить jdbc и по сути в консольке работать с бд в привычном окружении явы пошагово - иногда удобней отладчика. но опять-же это всё есть в обычной жвм

rukez ★★★★
()
Ответ на: комментарий от drsm

It provides a 100% support of ECMAScript 5.1.

никому не нужно это говно в 2020+.

GraalJs поддерживает кстати ES2020 и ES2021 на подлёте.

нет ли бенчей насколько js в graal тормознее ноды?

Из актуального вот здесь даже спор разработчиков GraalJs видел:

https://github.com/oracle/graaljs/issues/360#issuecomment-707004312

И ниже.

EXL ★★★★★
() автор топика
Ответ на: комментарий от rukez

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

Например рабочие процессы (workflows) - описания неких автоматизированных процессов, которые в шарике можно фигачить диаграммами. Предполагается, что некто (бизнес-аналитик) накидывает диаграмму процесса прям в веб интерфейсе или специальной тулзе, с описанием стадий и действий, через которые скажем проходит документ, сохраняет, и дальше все этим пользуются. И все это без привлечения погромистов.

Т.е. умозрительно можно предположить, что можно дать возможность продвинутому пользователю описывать логику процесса на яваскрипте (который попроще явы). Или макросы для подстановки данных в отчеты или генерируемые документы.

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

Ну или если брать типовой шариковский рабочий процесс - многоэтапное утверждение документа некоторым набором пользователей. Где еще он может исполняться, кроме как на сервере? Документ там, стейт процесса - тоже. Максимум «хайтека» что можно сделать - движок рабочих процессов вынести в отдельный сервис (что в шарике и сделали со временем).

Midael ★★★★★
()
Последнее исправление: Midael (всего исправлений: 5)
Ответ на: комментарий от Midael

Т.е. умозрительно можно предположить, что можно дать возможность продвинутому пользователю описывать логику процесса на яваскрипте (который попроще явы).

дык а чем он проще то? ява проще некуда, ибо она позволяет не напортачить на ровном месте.
и главное что если тебе надо связывать в одном жвм жс и яву, то либо тебе надо делать смычку, которая из хз какого кода жс всё сведёт к объектам явы, либо изначально синхронизировать классы и тогда листинг простых вещей на жс будет плюс-минус совпадать с явушкой, а сложных он просто не позволит сделать :-)

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

Т.е. умозрительно можно предположить

я умозрительно вижу такое в 1С - там, по сути, бейсик, который еще проще жс
но я не вижу что-бы:

  • в 1С руками что-то писали на нём сами бухгалтера. не потому что это сложно а потому что никто вменяемый не будет доверять бухгалтеру инжекции в данные - это гораздо дороже чем нанять человека который умеет писать под платформу
  • это всё мешали с чем-то еще

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

п.с. и это таки всё деды делали еще на яве ЕЕ, на которой есть 100500 проектов всяких мега и гипер корпоративных мс :-)

rukez ★★★★
()
Ответ на: комментарий от EXL

GraalJs поддерживает кстати ES2020 и ES2021 на подлёте.

да, это радует

почитал https://www.graalvm.org/reference-manual/js/NashornMigrationGuide/ они там еще и по security озаботились.

https://github.com/oracle/graaljs/issues/360#issuecomment-707004312

спасибо. довольно забавно, 70x, V8 разрывает в клоки, что больше похоже на правду.

но ворклоад довольно специфический, только больной человек будет в проде это запускать на GraalVM.

drsm ★★
()
Ответ на: комментарий от drsm

https://github.com/oracle/graaljs/issues/360#issuecomment-707004312

спасибо. довольно забавно, 70x, V8 разрывает в клоки, что больше похоже на правду

Там чел как-то криво бенчит. На проверку разрыв оказывается x7-15 на AOT компиляции, и x2.5 в режиме JIT. Очевидно, из-за недоработки AOT компиляция делается как-то криво. Вот вы примерно и поняли, почему столько лет к жаве не могли прикрутить AOT.

Ну а плохая производительность на единственном примере программы — это весьма прохладная история.

byko3y ★★★★
()
Ответ на: комментарий от rukez

нужно человеку для решения большинства реальных задач

Покажите мне этого человека и его задачи. Мне нужно, чтобы не жрало память, запускалось в пределах 100 мс, и задержка ответа также никогда не превышала 100 мс. Всё остальное переводит JVM в разряд капризных VM, которые перед практическим применением нужно обложить костылями и сотнями Гб оперативнйо памяти.

byko3y ★★★★
()
Последнее исправление: byko3y (всего исправлений: 1)
Ответ на: комментарий от byko3y

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

Так ты свою аватарку давно проверял? Человеку нужно, чтобы буфера не переполнялись.

anonymous
()
Ответ на: комментарий от byko3y

Ну а плохая производительность на единственном примере программы — это весьма прохладная история.

Это история про то, как работает оптимизированный под V8 код (acorn) на JVM.

На проверку разрыв оказывается x7-15 на AOT компиляции, и x2.5 в режиме JIT.

на прогретой JVM 15x.

в любом случае, тягаться с V8 в выполнении замороченного яваскрипта, это такое, бессмысленное занятие.

для практического применения в качестве glue code, выглядит кмк не плохо.

drsm ★★
()
Ответ на: комментарий от rukez

дык а чем он проще то? ява проще некуда, ибо она позволяет не напортачить на ровном месте

Сложна как язык общения программиста и комьпютера. Для неискушенного пользователя язык Java — это просто страшный кошмар, с ее:

Кококо<кудах> кукарек = new Кококо<кудах>()

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

и главное что если тебе надо связывать в одном жвм жс и яву, то либо тебе надо делать смычку, которая из хз какого кода жс всё сведёт к объектам явы

VM JS реализована на JVM. Вот тебе и вся смычка. Примерно та же история, например, с Jython — как в нем из жавы получать доступ к объектам Jython?

если ты хочешь сделать юзеру просто то сваргань ему простой человекопонятный интерфейс для скриптостроительства кубиками

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

byko3y ★★★★
()
Последнее исправление: byko3y (всего исправлений: 1)
Ответ на: комментарий от anonymous

Так ты свою аватарку давно проверял? Человеку нужно, чтобы буфера не переполнялись

Используй Rust или Go.

byko3y ★★★★
()
Ответ на: комментарий от byko3y

Когда я их последний раз смотрел, раст был в положении кота Шрёдингера в связи с сокращениями в мозиле и отделением от неё, а в го не было генериков и все обмазывались кодогенераторами. Что-то изменилось?

anonymous
()
Ответ на: комментарий от anonymous

Когда я их последний раз смотрел, раст был в положении кота Шрёдингера в связи с сокращениями в мозиле и отделением от неё

А типа десять лет развития Rust до этого тебе недостаточно, Мозила должна тащить раст до гроба?

в го не было генериков и все обмазывались кодогенераторами

Основной способ обобщенного программирования в Go — это интерфейсы. Утиная типизация делает работу с ними удивительно простой по сравнению с поддержкой интерфейсов другими языками со статической типизацией.

byko3y ★★★★
()
Ответ на: комментарий от byko3y

А типа десять лет развития Rust до этого тебе недостаточно, Мозила должна тащить раст до гроба?

Так я тоже впрягаться не хочу. Желающие спонсировать дальнейшую разработку уже есть?

Основной способ обобщенного программирования в Go — это интерфейсы. Утиная типизация делает работу с ними удивительно простой по сравнению с поддержкой интерфейсов другими языками со статической типизацией.

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

Мне правда интересно, стоит ли что-то из них потыкать, но заморачиваться ради очередного облома совсем неохота. Спасибо за инфу.

anonymous
()
Ответ на: комментарий от rukez

дык а чем он проще то? ява проще некуда, ибо она позволяет не напортачить на ровном месте.

Как ты думаешь, почему на джаве никто не программирует в блокноте?

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

anonymous
()
Ответ на: комментарий от anonymous

Я думаю, раз это проще жс, то шагов там должно быть меньше трех.

Там вообще один шаг - запускаешь jshell, начинаешь программировать :-)

Парни, у вас сильно застарелые взгляды на Яву, советую почитать что вводили отцы в 8-9 в помощь дедам, и что потом вводили в 11+ в назидание грядущим поколениям :-)

rukez ★★★★
()
Ответ на: комментарий от rukez

ну ты же понимаешь что необходимость перезагрузки приложения или VM не зависит от языка, который она исполняет, а зависит только от ленивости или криворукости создателя программы?

Этот человек не писал на лиспе или сишечке.

anonymous
()
Ответ на: комментарий от anonymous

Этот человек не писал на лиспе или сишечке.

Ты в любой программе на любом языке можешь вернуться в начало и переинициализировать переменные, достаточно начало сделать доступной функцией и переменные инициализировать функцией. Другое дело что обычно это лень делать, но эти никоим образом не ограничение языка/вм/со/положения звёзд на небе

rukez ★★★★
()
Ответ на: комментарий от byko3y

Но никто забесплатно, судя по всему, такой либы писать не будет.

Есть такая штука, как https://github.com/codemirror/CodeMirror

Его используют очень много где, тот же Gerrit, например. Но тянуть такое для подсветки синтаксиса как-то оверкильно.

EXL ★★★★★
() автор топика
Ответ на: комментарий от rukez

Там вообще один шаг - запускаешь jshell, начинаешь программировать :-)
Парни, у вас сильно застарелые взгляды на Яву, советую почитать что вводили отцы в 8-9 в помощь дедам, и что потом вводили в 11+ в назидание грядущим поколениям

Хорошо, сегодня я буду твоим учеником. Мне нужно распарсить XML. Какую строку мне ввести в jshell?

byko3y ★★★★
()
Ответ на: комментарий от EXL

Есть такая штука, как https://github.com/codemirror/CodeMirror
Его используют очень много где, тот же Gerrit, например. Но тянуть такое для подсветки синтаксиса как-то оверкильно

Конечно оверкильно, потому что это целый редактор.

byko3y ★★★★
()
Ответ на: комментарий от byko3y

Мне нужно распарсить XML. Какую строку мне ввести в jshell?

Если в дом, то первый же пример в гугле тебе намекает что листинг на Яве отличается от листинга на жс только наличием импортов и отловом ошибок, хорошо это или плохо (правильный ответ - хорошо) думай сам: https://java-course.ru/begin/xml/

Так что можешь смело вводить первый же пример

rukez ★★★★
()
Ответ на: комментарий от rukez

кстати проверил ради интереса - жшел позволяет не отлавливать ошибки принудительно так что отличия в листинге сводятся к импортам :-)

п.с. для совсем адептов жс есть:

javax.script.ScriptEngine;
javax.script.ScriptEngineManager;

которые то-же вполне себе работают

rukez ★★★★
()
Последнее исправление: rukez (всего исправлений: 1)
Ответ на: комментарий от rukez

в 1С руками что-то писали на нём сами бухгалтера. не потому что это сложно а потому что никто вменяемый не будет доверять бухгалтеру инжекции в данные - это гораздо дороже чем нанять человека который умеет писать под платформу

Иногда пишут «заклинания» при групповой обработке данных. Типа: https://infostart.ru/upload/iblock/f6a/f6a2cab7336ecefdf9ab0bcfb62c031f.JPG

monk ★★★★★
()
Ответ на: комментарий от monk

Иногда пишут «заклинания» при групповой обработке данных

если квалификации бухгалтера хватает, то почему бы и нет, хотя если он ошибётся то, помимо порчи данных (которая вполне может быть и после выборки, если форма потом чего-нить пишет обратно, типа данных в регистры накопления), это может привести и к приколам в налоговой (задекларировали лишний ноль в доходах? молодцы :-) ), и к порочным действиям руководства (да у нас тут рост прибылей аж на 300% по производству собачих фекалек, покупаем новый фекальковый цех … как это там минус пропал? мы уже оплатили всё) и к прочим коллапсам (как это ооо «жопуржец» получило прайс для ооо «пендехох»? они же теперь будут требовать себе такие-же цены)

так что в идеальном мире, программист знает где чего лежит и может с этими данными делать чего надо, а бухгалтер просто пишет ему записку что с ними нужно делать

ну и да, там выборки это по сути просто аргумент функции выбора из бд, на явушке ты можешь намного больше - очень хороший старт описан в MethodInvocationUtils тута: https://stackoverflow.com/questions/935175/convert-string-to-code

с минимумом переделок позволяет просто пихнуть текстом например вот такой скрипт (хоть из поля ввода на форме :-) ):

import ru.topol3.Client.Client;
import ru.topol3.Client.ClientsList;
import ru.topol3.Devices.Device;

public class Script {
	public static void run() {
		Client client = ClientsList.getClient(0);
		Device dev = client.getDevice(0);
		System.out.println(dev.getName());
		dev.setName("Замена имени из скрипта");
	}
}

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

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

rukez ★★★★
()
Последнее исправление: rukez (всего исправлений: 2)
Ответ на: комментарий от rukez
var xml2js = require('xml2js');
var sMyString = '<a id="a"><b id="b">hey!</b></a>';
new xml2js.Parser().parseString(sMyString, (err, result) => { console.dir(result) });
{ a: { '$': { id: 'a' }, b: [ [Object] ] } }
{
  comment: '',
  sgmlDecl: '',
  textNode: '',
  tagName: '',
  doctype: '',
  procInstName: '',
  procInstBody: '',
  entity: '',
  attribName: '',
  attribValue: '',
  cdata: '',
  script: '',
  c: '',
  q: '',
  bufferCheckPosition: 65536,
  opt: { trim: false, normalize: false, xmlns: false, lowercase: undefined },
  looseCase: 'toUpperCase',
  tags: [],
  sawRoot: false,
  closedRoot: false,
  closed: false,
  error: null,
  tag: null,
  strict: true,
  noscript: true,
  state: 0,
  strictEntities: undefined,
  ENTITIES: {},
  attribList: [],
  trackPosition: true,
  column: 0,
  line: 0,
  position: 0,
  errThrown: false,
  onerror: [Function],
  onend: [Function],
  ended: true,
  onopentag: [Function],
  onclosetag: [Function],
  ontext: [Function],
  oncdata: [Function],
  startTagPosition: 29
}

https://java-course.ru/begin/xml/
Так что можешь смело вводить первый же пример

«Первый пример» там будет на 33 строки, без коментов и единственной скобочки. У меня команды на... ну хорошо, четыре строки, если лямбду вынести отдельно.

byko3y ★★★★
()
Ответ на: комментарий от rukez

с минимумом переделок позволяет просто пихнуть текстом например вот такой скрипт (хоть из поля ввода на форме :-) ):

import ru.topol3.Client.Client;
...
и получить доступ к нужным переменным, поправить их из скрипта, позапускать чего надо и вообще работать на полных правах захардкоженного кода

А теперь как это пишется на ES JS:

import { ClientsList } from 'topol3';

var dev = ClientsList[0].devices[0];
console.log(dev.name);
dev.name = 'Замена имени из скрипта';
byko3y ★★★★
()
Ответ на: комментарий от byko3y

«Первый пример» там будет на 33 строки, без коментов и единственной скобочки. У меня команды на… ну хорошо, четыре строки, если лямбду вынести отдельно.

а xml2js входит в ванильный JS?
мой пример на ванильной яве, так то ты можешь обернуть его в свою библиотеку и вызывать вообще одной строкой

тем более что действия для строительства дома один фиг будут одинаковыми - вычитать файл, создать дом, распарсить содержимое в дом …

но если мы боремся за кол-во строчек на соревнованиях по плохочитаемому коду то вот тебе однострочный парс:

NodeList books = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse("BookCatalog.xml").getDocumentElement().getChildNodes();

всё что нужно акромя - импорты, но если ты идёшь по пути библиотеки то просто импортируй их в другом файле и импортируй его :-))

rukez ★★★★
()
Ответ на: комментарий от byko3y

А теперь как это пишется на ES JS: ClientsList[0].devices[0]

и это совсем не то потому что:
Client client = ClientsList.getClient(0);
например, вызывает ClientsList.connectDefault() если в 0 == null; а client.getDevice(0) может принимать не только индекс но и UUID, т.е. если бы мы брали конкретный прибор по уиду то не прокатило бы

console.log(dev.name);

в getName() лежит сборка строки из строки с именем, типа прибора, ip адреса, адреса в последовательном порту и т.п.

dev.name = ‘Замена имени из скрипта’;

в целом прокатит, если этот метод ломает private доступ :-)

import { ClientsList } from ‘topol3’;

а если надо вот так:

public class ScriptC {
	public static void run() {
		Client client = ClientsList.getClient(0);
		synchronized (ClientsList.getDevices()) {					
			Device dev = client.getDevice(0);
			System.out.println(dev.getName());
			dev.setName("Замена имени из скрипта");
		}
	}
}

будет работать?

rukez ★★★★
()
Последнее исправление: rukez (всего исправлений: 1)
Ответ на: комментарий от byko3y

А теперь как это пишется на ES JS:

кстати можно и в яве можно ужать импорты, но это не так читаемо:

import ru.topol3.Client.ClientsList;

public class Script {
	public static void run() {
			System.out.println( ClientsList.getClient(0).getDevice(0).getName());
			ClientsList.getClient(0).getDevice(0).setName("Замена имени из скрипта");
	}
}

разница в том что в JS ты работаешь с не особо понятно чем через прослойку, а в яве ты работаешь совершенно нативно с полноценными объектами, которым доступно всё, включая все поля (притом на уровне ран-тайма т.к. с синхронизацией и т.п.), рефлекшны и т.п., притом это всё легко пишется в той-же IDE как обычный код, и этот код можно юзать и в основной программе (т.е. в скрипты можно просто дергать готовые куски кода программы, в которые вхардкожены нужные значения переменных) - это ИМХО намного удобней и проще чем писать на другом языке сильно абстрагированный код-дублёр, при этом заметь что реальной разницы в синтаксисе или сложности нет

rukez ★★★★
()
Последнее исправление: rukez (всего исправлений: 1)
Ответ на: комментарий от rukez

а xml2js входит в ванильный JS?

Ты забываешь, что далеко не все языковые среды поставляются в виде монолита из сотен прикладных библиотек.

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

Назад риторика была «просто запусти jshell», теперь она сменилась на «просто еще напиши функцию». Кому предлагаешь это делать? Бухгалтеру?

но если мы боремся за кол-во строчек на соревнованиях по плохочитаемому коду то вот тебе однострочный парс

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

Dependency Injection что это за беспредел? (комментарий)

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

всё что нужно акромя - импорты, но если ты идёшь по пути библиотеки то просто импортируй их в другом файле и импортируй его

Ага, всего-лишь экран импортов нужен — всё просто.

byko3y ★★★★
()
Ответ на: комментарий от rukez

Client client = ClientsList.getClient(0);
например, вызывает ClientsList.connectDefault() если в 0 == null; а client.getDevice(0) может принимать не только индекс но и UUID, т.е. если бы мы брали конкретный прибор по уиду то не прокатило бы
в getName() лежит сборка строки из строки с именем, типа прибора, ip адреса, адреса в последовательном порту и т.п.

Представь себе, в качестве ключа ассоциативного массива в JS может выступать что угодно: хоть число, хоть строка, хоть объект, хоть Symbol. И геттеры-сеттеры есть, причем, дают они чистый красивый интерфейс свойства, потому спора «нужны ли геттеры или можно просто поле» в JS в принципе не возникает, потому что есть то и другое сразу, и легко, и красиво, и понятно.

в целом прокатит, если этот метод ломает private доступ

И потому не ломает.

а если надо вот так
synchronized (ClientsList.getDevices()) {

У JS изначально модель многопоточности «shared none», потому проблема одновременного доступа не возникает. Возникает проблема того, как эффективно перекинуть данные между потоками.

byko3y ★★★★
()
Ответ на: комментарий от rukez

разница в том что в JS ты работаешь с не особо понятно чем через прослойку, а в яве ты работаешь совершенно нативно с полноценными объектами, которым доступно всё, включая все поля (притом на уровне ран-тайма т.к. с синхронизацией и т.п.), рефлекшны и т.п.,

В JS ты можешь работать с либой на чистом JS, можно дерагать и нативные либы, примерно как JNI. И чтение структуры объекта есть, и модификация структуры объекта.

притом это всё легко пишется в той-же IDE как обычный код

А JS легко пишется в блокноте или консоли.

byko3y ★★★★
()
Ответ на: комментарий от byko3y

Ты забываешь, что далеко не все языковые среды поставляются в виде монолита из сотен прикладных библиотек. Назад риторика была «просто запусти jshell», теперь она сменилась на «просто еще напиши функцию». Кому предлагаешь это делать? Бухгалтеру?

ты берешь стороннюю библиотеку, которая делает 4 шага и вызываешь её в 4х строчках
я тебе показал полный листинг без библиотек, но ты можешь точно так-же взять стороннюю библиотеку на 4 шага и точно так-же вызывать её в 1-2-4х строчках

в чем собсно разница?

Твоя претензия необоснована, потому что в коде на JS лямбду можно перенести на другую строчку и читаемость станет прекрасная, А твой пример читаемым сделать не получится.

ты понимаешь что в моём примере происходит то-же самое, что и в твоём?
что именно из моего примера, ты считаешь, можно просто взять и выкинуть, без последствий для логики программы и читаемости?

  • отлов исключений? ага, в серверной вм самое отличное решение
  • вербузный импорт? можешь импортировать с * - будет 2 строчки
    в остальном внезапно (с) код на жс и яве одинаковый

Причем, эта вырвиглазность не оправдана языком — это просто библиотеки жавы так криво спроектированы

а ты точно понял о чём там речь шла? это для создания классов по мете/типу с внешним указанием, внезапно (с) на любом другом языке будет точно так-же - я там вроде пример показывал как можно сделать проще

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

не нравится не используй - никто же не заставляет

Ага, всего-лишь экран импортов нужен — всё просто.

кол-во импортов зависит только от тебя - в последнем примере всё сведено к одному импорту.
если тебе не нравятся импорты, то ты можешь ударить по столу кулаком и всё свети к одному пакету - будет ровно ноль импортов - в этом фишка явы, то что начинающие пытаются отрыгнуть за непониманием, на самом деле годнота и спасает олёшек от случайных печалей - например использования класса List из Awt вместо Util ;-)

Представь себе, в качестве ключа ассоциативного массива в JS может выступать что угодно: хоть число, хоть строка, хоть объект, хоть Symbol. И геттеры-сеттеры есть, причем, дают они чистый красивый интерфейс свойства, потому спора «нужны ли геттеры или можно просто поле» в JS в принципе не возникает, потому что есть то и другое сразу, и легко, и красиво, и понятно.

ты точно программист? :-)
я предлагаю тебе представить то, что твой код, если его взять и выполнить вместо моего кода, сделает совершенно не то, что должен сделать, ибо все вызовы в моём коде, это далеко не просто выбор/установка по индексу массива, и речь именно о том, что мой метод использования скриптов, позволяет выполнять в рантайме всё то-же что и уже болтающийся там - вызывать функции объектов (а не просто перебирать значения полей), использовать синхронизацию и т.п. - перечитай еще разок мои комментарии по замене и представь что выполняется твой код построчно вместо моего :-)

У JS изначально модель многопоточности «shared none», потому проблема одновременного доступа не возникает. Возникает проблема того, как эффективно перекинуть данные между потоками.

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

В JS ты можешь работать с либой на чистом JS, можно дерагать и нативные либы, примерно как JNI. И чтение структуры объекта есть, и модификация структуры объекта.

я кажись понял что ты не понял о чем речь :-)
речь не о JS vs Java, речь о том что внедрять JS в исполняемый Java файл - так себе затея, ибо JS исполняется несколько отрешенно и имеет сильно черезпрослойный доступ к объектам реального исполняемого кода явы, в то время как инжекции в яву кода на самой яве - вполне себе не проблемны и легко организуются с полным контролем всего и вся, будто бы инжектированный код всегда был в твоём приложении

п.с.

А JS легко пишется в блокноте или консоли.

а для явы теперь своя интерактивная консоль из коробки идёт :-P

rukez ★★★★
()
Последнее исправление: rukez (всего исправлений: 1)
Ответ на: комментарий от byko3y

Не так давно проблему вырвиглазности жавовых XML парсеров как раз разбирали:

Кстати, это довольно занимательный парадокс, что с такими вот неудобными интерфейсами парсеров экосистема старой Java’ы так сильно была завязана на XML. До сих пор эти портянки везде встречаются.

EXL ★★★★★
() автор топика
Ответ на: комментарий от rukez

а в яве ты работаешь совершенно нативно с полноценными объектами

Кстати возвращаясь к альфреске и шарику. Не знаю как в альфреске, но в шарике - точно нет. Так как платформа заточена на хранение произвольных данных настраиваемых на лету, там не будет ни заранее известной схемы, ни модели в коде. Будет что-то типа словаря ColumnName-ColumnValue

Midael ★★★★★
()
Ответ на: комментарий от rukez

ты берешь стороннюю библиотеку, которая делает 4 шага и вызываешь её в 4х строчках

Я тебя попросил привести мне простой пример, который я мог бы использовать в jshell. Ты мне дал какую-то муть, и теперь я же виноват, что ты не можешь ответить за свои слова?

ты понимаешь что в моём примере происходит то-же самое, что и в твоём?

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

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

Если ты не заметил — код на JS обрабатывает ошибки.

вербузный импорт? можешь импортировать с * - будет 2 строчки

В JS тоже есть импорт по звездочке. И тогда импорта становятся еще короче.

а ты точно понял о чём там речь шла? это для создания классов по мете/типу с внешним указанием, внезапно (с) на любом другом языке будет точно так-же

Если бы ты владел более чем одним языком, то не писал бы такого.

твой код, если его взять и выполнить вместо моего кода, сделает совершенно не то, что должен сделать, ибо все вызовы в моём коде, это далеко не просто выбор/установка по индексу массив

Мой код не представляет собой выборку по индексу массива. Я тебе написал это два раза — теперь третий.

речь не о JS vs Java, речь о том что внедрять JS в исполняемый Java файл - так себе затея, ибо JS исполняется несколько отрешенно и имеет сильно черезпрослойный доступ к объектам реального исполняемого кода явы

https://www.graalvm.org/reference-manual/js/JavaInteroperability/

var file = new (Java.type('java.io.File'))("test.md");
var fileName = file.getName();
byko3y ★★★★
()
Ответ на: комментарий от EXL

Кстати, это довольно занимательный парадокс, что с такими вот неудобными интерфейсами парсеров экосистема старой Java’ы так сильно была завязана на XML. До сих пор эти портянки везде встречаются

Меня смущает больше то, что с таким неудобным интерфейсом самого языка им вообще кто-то пользуется. А парсеры XML? Ну да, слегка кривоваты.

byko3y ★★★★
()
Ответ на: комментарий от byko3y

Представь себе, в качестве ключа ассоциативного массива в JS может выступать что угодно: хоть число,

Перестань нести бред.

anonymous
()
Ответ на: комментарий от byko3y

Я тебя попросил привести мне простой пример, который я мог бы использовать в jshell. Ты мне дал какую-то муть, и теперь я же виноват, что ты не можешь ответить за свои слова?

ты точно не чукча, который писатель? я тебе его даже в виде однострока показывал - вот как в жшел можно тремя командами получить XML в распарсеном объекте:

|  Welcome to JShell -- Version 11.0.9
|  For an introduction type: /help intro

jshell> import javax.xml.parsers.*

jshell> import org.w3c.dom.*;

jshell> NodeList books = DocumentBuilderFactory.newInstance().newDocumentBuilder
().parse("text.xml").getDocumentElement().getChildNodes();
books ==> [recipe: ]

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

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

Если ты не заметил — код на JS обрабатывает ошибки.

не заметил - ерр пустой

Если бы ты владел более чем одним языком, то не писал бы такого.

я сдаюсь, честно

тебе говорят что что для распаршивания xml’ки, что для других типовых действий на любом языке надо пройти одни и те-же шаги, но ты продолжаешь упорствовать. я не против, верь что в черных ящиках твоих библиотек существует особая магия, которая проскакивает логику, мне как-то пофигу :-)

Мой код не представляет собой выборку по индексу массива. Я тебе написал это два раза — теперь третий.

напиши четвертый, но только не как создать голый объект а как сделать:

  • device.setName() на существующем объекте
  • синхронизацию по существующему объекту

и даже если у тебя получится, обьясни на пальцах в чём прикол этого внедрения бульдога в носорога?

rukez ★★★★
()
Ответ на: комментарий от rukez

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

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

не заметил - ерр пустой

Хорошо, пусть будет:

if (error) {
    console.log(err);
    return;
}

6 строчек, с обработкой ошибок.

byko3y ★★★★
()
Последнее исправление: byko3y (всего исправлений: 1)
Ответ на: комментарий от byko3y

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

лол, ява то это позволяет из коробки и без внешних либ
хочется с либами то берешь хоть апач хоть еще 100500 вариантов в гугле на любой вкус

6 строчек, с обработкой ошибок.

круть, против трёх в жшел :-)
и главное с внешней нахлобучкой в виде грааля

удачи в эксплуатации (с), жаль так и не увидели примеров интеропа с реальными объектами :-)

rukez ★★★★
()
Ответ на: комментарий от rukez

тебе говорят что что для распаршивания xml’ки, что для других типовых действий на любом языке надо пройти одни и те-же шаги

В Java шагов всегда больше. Хоть с XML DocumentBuilderFactory.newInstance().newDocumentBuilder ().parse(«text.xml»).getDocumentElement().getChildNodes() против DOM.build(«text.xml»).childs()

Я когда в 1С с Excel на OpenOffice переходил ужасался как

Excel = Новый COMОбъект("Excel.application");
Excel.WorkBooks.Open(ПолноеИмяФайла);
Лист = Excel.Sheets(1); // Первый лист по индексу
ВсегоСтрок = Лист.Cells(1,1).SpecialCells(11).Row;
Данные = Лист.Cells(Строка, Колонка).Value;

превращается в

OpenOffice = Новый ComОбъект("com.sun.star.ServiceManager"); // Создаем СОМ-объект
 
 scr = Новый ComОбъект("MSScriptControl.ScriptControl");    
 scr.language = "javascript";
 scr.eval("MassivParametrov = new Array()");
 MassivParametrov = scr.eval("MassivParametrov");
 scr.AddObject("OpenOffice", OpenOffice);
 scr.eval("MassivParametrov[0]=OpenOffice.Bridge_GetStruct('com.sun.star.beans.PropertyValue')");
 scr.eval("MassivParametrov[0].Name='Hidden'");
 scr.eval("MassivParametrov[0].Value=true");
 
 Desktop = OpenOffice.CreateInstance("com.sun.star.frame.Desktop"); // Создаем Desktop
 ИмяФайла =  СтрЗаменить(ПолноеИмяФайла," ","%20" );
 ИмяФайла =  СтрЗаменить(ИмяФайла,"\","/");
 URL = "file://localhost/" + ИмяФайла; // Правильно формируем имя файла
 Doc = Desktop.LoadComponentFromURL(URL, "_blank", 0, MassivParametrov);
 
 Doc.lockControllers();
 Doc.addActionLock();
 
 Sheets = Doc.GetSheets();
 Лист = Sheets.GetByIndex(0); // Открываем первый лист по индексу
 oCell = Лист.GetCellbyPosition(0, 0);
 oCursor = Лист.createCursorByRange(oCell);
 oCursor.GotoEndOfUsedArea(Истина);
 aAddress = oCursor.RangeAddress;
 ВсегоСтрок = aAddress.EndRow;
 Данные = Лист.getCellByPosition(Колонка,Строка).getText().String();
monk ★★★★★
()
Ответ на: комментарий от monk

Я когда в 1С с Excel на OpenOffice переходил ужасался как

Хм-м-м, я вот docx через JS формирую, и с подобными проблемами не сталкивался. Так что это скорее упрек тем, кто в 1С добавил такие интерефейсы. Особо радует

scr = Новый ComОбъект("MSScriptControl.ScriptControl");
scr.language = "javascript";

byko3y ★★★★
()
Ответ на: комментарий от byko3y

Меня смущает больше то, что с таким неудобным интерфейсом самого языка им вообще кто-то пользуется.

Куча батареек с простой установкой, штабильность, строгая статическая типизация, выбор ынтерпрайза и Android привели к тому, что Java стала одним из самых популярных мейнстримовых языков сегодня.

Если бы не эти факторы, те неудобства, которые возникают в процессе разработки чего-либо на Java быстро бы переметнули кучу разработчиков на другие языки и технологии ещё в середине нулевых. Вот как с Perl видимо случилось.

Сейчас, конечно, всякие там Kotlin, Scala, Groovy и Clojure откусывают кусок популярности у Java, поэтому Oracle тоже зашевелился и всякий сахарок начал туда подвозить, которые делают разработку несколько удобнее.

EXL ★★★★★
() автор топика
Ответ на: комментарий от byko3y

Хм-м-м, я вот docx через JS формирую

При чём тут docx? Это интерфейс к OpenOffice.Calc.

Особо радует scr

А что делать? Объект OpenOffice наружу не экспортируется, а структуру com.sun.star.beans.PropertyValue для com.sun.star.frame.Desktop.LoadComponentFromURL передать надо.

monk ★★★★★
()
Ответ на: комментарий от monk

Я когда в 1С с Excel на OpenOffice переходил ужасался как

превращается в

Вот это я понимаю True Scripting !

2 @rukez

Вот для случая Enterprise Level задач типа: «третьего дня завезли новые фичи. от правой подситемы приходит джсон строкой, от левой пачка csv, + у нас тут еще есть мега наша Объектная Модель. надо вывалить все это в отчет. должно быть готово вчера, послезавтра это будет никому не нужно. послезавтра будет другое говно.», ты выберешь Java ? любишь боль? :)

drsm ★★
()
Ответ на: комментарий от drsm

Вот для случая Enterprise Level задач типа: «третьего дня завезли новые фичи. от правой подситемы приходит джсон строкой, от левой пачка csv, + у нас тут еще есть мега наша Объектная Модель. надо вывалить все это в отчет. должно быть готово вчера, послезавтра это будет никому не нужно. послезавтра будет другое говно.», ты выберешь Java ?

В любой день недели!
Почему? Потому что это будет работать и это будет легко и понятно.

Пруф даже есть, 100% Ява, на 99% ванильная: Java'чка крашенная

Охраняет, например, Шереметьево, так что довольно таки энтерпрайзненько :-)

rukez ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.