├── .circleci └── config.yml ├── .cspell.json ├── .eslintrc.js ├── .github ├── FUNDING.yml ├── linters │ ├── .checkov.yml │ └── .yamllint.yml └── workflows │ ├── deploy-beta.yml │ ├── deploy-release.yml │ ├── github-dependents-info.yml │ ├── mega-linter.yml │ └── test.yml ├── .gitignore ├── .lycheeignore ├── .mega-linter.yml ├── .vscode └── launch.json ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── docs └── github-dependents-info.md ├── examples ├── cli_app │ ├── README.md │ ├── lib │ │ ├── index.js │ │ ├── java-caller-config.json │ │ └── java │ │ │ └── JavaCallerTester.jar │ └── package.json └── module_app │ ├── lib │ ├── index.js │ └── java │ │ └── JavaCallerTester.jar │ └── package.json ├── lib ├── cli.js ├── index.js └── java-caller.js ├── package-lock.json ├── package.json ├── renovate.json └── test ├── helpers ├── common.js └── init.js ├── java-caller.test.js ├── java-install.test.js └── java ├── dist └── com │ └── nvuillam │ └── javacaller │ └── JavaCallerTester.class ├── jar ├── JavaCallerTester.jar ├── JavaCallerTesterRunnable.jar ├── JavaCallerTesterRunnable.zip ├── manifest-runnable │ └── Manifest.txt └── manifest │ └── Manifest.txt └── src └── com └── nvuillam └── javacaller └── JavaCallerTester.java /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | orbs: 4 | win: circleci/windows@5.1.0 5 | 6 | jobs: 7 | # JDK 8 Node 12 8 | debian-jdk-8-node-16: 9 | docker: 10 | - image: openjdk:8 11 | steps: 12 | - checkout 13 | - run: 14 | name: Install base tools 15 | command: apt-get update && apt-get upgrade -y && apt-get -y install wget zip unzip sudo && apt-get clean && echo 'Installed linux dependencies' 16 | - run: 17 | name: Install node 18 | command: curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get update && apt-get install -y nodejs 19 | - run: 20 | name: Install dependencies 21 | command: npm ci 22 | - run: 23 | name: Testing 24 | command: npm run test:debug 25 | 26 | # JDK 9 Node 12 27 | debian-jdk-9-node-18: 28 | docker: 29 | - image: openjdk:9 30 | steps: 31 | - checkout 32 | - run: 33 | name: Install base tools 34 | command: apt-get update && apt-get upgrade -y && apt-get -y install wget zip unzip sudo && apt-get clean && echo 'Installed linux dependencies' 35 | - run: 36 | name: Install node 37 | command: curl -sL https://deb.nodesource.com/setup_18.x | bash - && apt-get update && apt-get install -y nodejs 38 | - run: 39 | name: Install dependencies 40 | command: npm ci 41 | - run: 42 | name: Testing 43 | command: npm run test 44 | 45 | # JDK 10 Node 12 46 | debian-jdk-10-node-18: 47 | docker: 48 | - image: openjdk:10 49 | steps: 50 | - checkout 51 | - run: 52 | name: Install base tools 53 | command: apt-get update && apt-get upgrade -y && apt-get -y install wget zip unzip sudo && apt-get clean && echo 'Installed linux dependencies' 54 | - run: 55 | name: Install node 56 | command: curl -sL https://deb.nodesource.com/setup_18.x | bash - && apt-get update && apt-get install -y nodejs 57 | - run: 58 | name: Install dependencies 59 | command: npm ci 60 | - run: 61 | name: Testing 62 | command: npm run test 63 | 64 | # JDK 11 Node 12 65 | debian-jdk-11-node-18: 66 | docker: 67 | - image: openjdk:11.0.16 68 | steps: 69 | - checkout 70 | - run: 71 | name: Install base tools 72 | command: apt-get update && apt-get upgrade -y && apt-get -y install wget zip unzip sudo && apt-get clean && echo 'Installed linux dependencies' 73 | - run: 74 | name: Install node 75 | command: curl -sL https://deb.nodesource.com/setup_18.x | bash - && apt-get update && apt-get install -y nodejs 76 | - run: 77 | name: Install dependencies 78 | command: npm ci 79 | - run: 80 | name: Testing 81 | command: npm run test 82 | 83 | # JDK 12 Node 12 84 | debian-jdk-12-node-18: 85 | docker: 86 | - image: openjdk:12-oracle 87 | steps: 88 | - checkout 89 | - run: 90 | name: Install base tools 91 | command: apt-get update && apt-get upgrade -y && apt-get -y install wget zip unzip sudo && apt-get clean && echo 'Installed linux dependencies' 92 | - run: 93 | name: Install node 94 | command: curl -sL https://deb.nodesource.com/setup_18.x | bash - && apt-get update && apt-get install -y nodejs 95 | - run: 96 | name: Install dependencies 97 | command: npm ci 98 | - run: 99 | name: Testing 100 | command: npm run test 101 | 102 | # No Java & Node latest 103 | no-java-node-latest: 104 | docker: 105 | - image: circleci/node:latest 106 | steps: 107 | - checkout 108 | - run: 109 | name: Install dependencies 110 | command: npm ci 111 | - run: 112 | name: Testing 113 | command: npm run test:coverage 114 | - run: 115 | name: Submitting code coverage to codecov 116 | command: | 117 | ./node_modules/.bin/nyc report --reporter text-lcov > coverage.lcov 118 | curl -s https://codecov.io/bash | bash 119 | 120 | # Java 17 & Node latest 121 | java-17-node-latest: 122 | docker: 123 | - image: circleci/openjdk:17.0.1-buster-node 124 | steps: 125 | - checkout 126 | - run: 127 | name: Install dependencies 128 | command: npm ci 129 | - run: 130 | name: Testing 131 | command: npm run test:debug 132 | 133 | # Java 21 & Node latest 134 | java-21-node-latest: 135 | docker: 136 | - image: cimg/openjdk:21.0.6-node 137 | steps: 138 | - checkout 139 | - run: 140 | name: Install dependencies 141 | command: npm ci 142 | - run: 143 | name: Testing 144 | command: npm run test:debug 145 | 146 | windows: 147 | executor: 148 | name: win/default 149 | shell: powershell.exe 150 | steps: 151 | - checkout 152 | - run: 153 | name: Install dependencies 154 | command: npm ci 155 | - run: 156 | name: Testing 157 | command: npm run test 158 | 159 | # As we use free version of CircleCI, uncomment jobs only if there are some detected issues, else debian-jdk-8/11-node-12 are enough 160 | workflows: 161 | version: 2 162 | "java-caller-lint-build-test": 163 | jobs: 164 | - debian-jdk-8-node-16 165 | # - debian-jdk-9-node-12 166 | # - debian-jdk-10-node-12 167 | # - debian-jdk-11-node-12 168 | # - debian-jdk-12-node-12 JDK12 image not working because of apt-get not found ... TODO: investigate 169 | - no-java-node-latest 170 | - java-17-node-latest 171 | - java-21-node-latest 172 | - windows 173 | -------------------------------------------------------------------------------- /.cspell.json: -------------------------------------------------------------------------------- 1 | { 2 | "ignorePaths": [ 3 | "**/node_modules/**", 4 | "**/vscode-extension/**", 5 | "**/.git/**", 6 | ".vscode", 7 | "package-lock.json", 8 | "**/megalinter-reports/**", 9 | "**/docs/github-dependents-info.md" 10 | ], 11 | "language": "en", 12 | "version": "0.1", 13 | "words": [ 14 | "BETAID", 15 | "CIRCLECIPIPELINES", 16 | "CLASSPATH", 17 | "Classpath", 18 | "Gowans", 19 | "Inclusivity", 20 | "KICS", 21 | "PROSELINT", 22 | "Perso", 23 | "SIGINT", 24 | "Sotiris", 25 | "Vas", 26 | "Vuillamy", 27 | "badgemarkdownfile", 28 | "cimg", 29 | "circleci", 30 | "classpath", 31 | "classpaths", 32 | "codecov", 33 | "customarg", 34 | "cvfm", 35 | "danunafig", 36 | "distrib", 37 | "djukxe", 38 | "javac", 39 | "javacaller", 40 | "javaw", 41 | "lcov", 42 | "lycheeignore", 43 | "markdownfile", 44 | "markdownlint", 45 | "megalinter", 46 | "minstars", 47 | "myfolder", 48 | "myjar", 49 | "nawak", 50 | "nico", 51 | "nimpor", 52 | "njre", 53 | "nvuillam", 54 | "oxsecurity", 55 | "preid", 56 | "quoi", 57 | "runned", 58 | "socio", 59 | "someflag", 60 | "someflagwithvalue", 61 | "temurin", 62 | "unhack", 63 | "unittests" 64 | ] 65 | } 66 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | es6: true 5 | }, 6 | extends: [ 7 | 'eslint:recommended' 8 | ], 9 | globals: { 10 | Atomics: 'readonly', 11 | SharedArrayBuffer: 'readonly', 12 | "module": true, 13 | "require": true, 14 | "process": true, 15 | "__dirname": true, 16 | "describe": true, 17 | "it": true, 18 | "globalThis": true, 19 | "beforeEach": true 20 | }, 21 | parser: "@babel/eslint-parser", 22 | parserOptions: { 23 | ecmaVersion: 2018, 24 | requireConfigFile: false, 25 | sourceType: "module" 26 | }, 27 | rules: { 28 | "indent": "off" // Managed by prettier 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [nvuillam] 4 | -------------------------------------------------------------------------------- /.github/linters/.checkov.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # You can see all available properties here: https://github.com/bridgecrewio/checkov#configuration-using-a-config-file 3 | quiet: true 4 | skip-check: 5 | - CKV_DOCKER_2 6 | - CKV_CIRCLECIPIPELINES_1 7 | - CKV_CIRCLECIPIPELINES_2 8 | -------------------------------------------------------------------------------- /.github/linters/.yamllint.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ########################################### 3 | # These are the rules used for # 4 | # linting all the yaml files in the stack # 5 | # NOTE: # 6 | # You can disable line with: # 7 | # # yamllint disable-line # 8 | ########################################### 9 | extends: default 10 | rules: 11 | braces: 12 | max-spaces-inside: 1 13 | document-start: disable 14 | new-lines: 15 | level: warning 16 | type: unix 17 | line-length: 18 | max: 500 19 | comments: 20 | min-spaces-from-content: 1 # Used to follow prettier standard: https://github.com/prettier/prettier/pull/10926 21 | truthy: disable 22 | -------------------------------------------------------------------------------- /.github/workflows/deploy-beta.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # 3 | # Documentation: 4 | # https://help.github.com/en/articles/workflow-syntax-for-github-actions 5 | # 6 | 7 | ####################################### 8 | # Start the job on all push to master # 9 | ####################################### 10 | name: 'Build & Deploy - Beta' 11 | on: 12 | push: 13 | branches: 14 | - main 15 | - master 16 | 17 | permissions: read-all 18 | 19 | concurrency: 20 | group: ${{ github.ref_name }}-${{ github.workflow }} 21 | cancel-in-progress: true 22 | 23 | ############### 24 | # Set the Job # 25 | ############### 26 | jobs: 27 | 28 | # Deploy to NPM 29 | deploy_to_npm: 30 | name: Deploy to NPM (beta) 31 | runs-on: ubuntu-latest 32 | permissions: read-all 33 | environment: 34 | name: beta 35 | steps: 36 | - uses: actions/checkout@v4 37 | - uses: actions/setup-node@v4.4.0 38 | with: 39 | node-version: "18.x" 40 | registry-url: "https://registry.npmjs.org" 41 | scope: nvuillam 42 | - run: npm ci 43 | - run: | 44 | git config --global user.name nvuillam 45 | git config --global user.email nicolas.vuillamy@gmail.com 46 | - run: BETAID=$(date '+%Y%m%d%H%M') && npm version prerelease --preid="beta$BETAID" 47 | shell: bash 48 | - run: npm publish --tag beta 49 | env: 50 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 51 | -------------------------------------------------------------------------------- /.github/workflows/deploy-release.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # 3 | # Documentation: 4 | # https://help.github.com/en/articles/workflow-syntax-for-github-actions 5 | # 6 | 7 | ####################################### 8 | # Start the job on all push to master # 9 | ####################################### 10 | name: 'Build & Deploy - RELEASE' 11 | on: 12 | release: 13 | # Want to run the automation when a release is created 14 | types: ['created'] 15 | 16 | permissions: read-all 17 | 18 | concurrency: 19 | group: ${{ github.ref_name }}-${{ github.workflow }} 20 | cancel-in-progress: true 21 | 22 | ############### 23 | # Set the Job # 24 | ############### 25 | jobs: 26 | deploy_to_npm: 27 | name: Deploy to NPM (release) 28 | runs-on: ubuntu-latest 29 | permissions: read-all 30 | environment: 31 | name: release 32 | steps: 33 | - uses: actions/checkout@v4 34 | # Setup .npmrc file to publish to npm 35 | - uses: actions/setup-node@v4.4.0 36 | with: 37 | node-version: "18.x" 38 | registry-url: "https://registry.npmjs.org" 39 | scope: nvuillam 40 | - run: npm ci 41 | - run: | 42 | git config --global user.name nvuillam 43 | git config --global user.email nicolas.vuillamy@gmail.com 44 | - run: npm publish 45 | env: 46 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 47 | -------------------------------------------------------------------------------- /.github/workflows/github-dependents-info.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # GitHub Dependents Info workflow 3 | # More info at https://github.com/nvuillam/github-dependents-info/ 4 | name: GitHub Dependents Info 5 | 6 | # Let by default 7 | on: 8 | # On manual launch 9 | workflow_dispatch: 10 | # On every push on selected branches (usually just main) 11 | push: 12 | branches: [main, setup-gdi] 13 | # Scheduled interval: Use CRON format https://crontab.guru/ 14 | schedule: 15 | - cron: "0 0 * * 0" # Every sunday at midnight 16 | 17 | permissions: read-all 18 | 19 | concurrency: 20 | group: ${{ github.ref }}-${{ github.workflow }} 21 | cancel-in-progress: true 22 | 23 | jobs: 24 | build: 25 | name: GitHub Dependents Info 26 | runs-on: ubuntu-latest 27 | permissions: 28 | contents: write 29 | pull-requests: write 30 | steps: 31 | # Git Checkout 32 | - name: Checkout Code 33 | uses: actions/checkout@v4 34 | with: 35 | token: ${{ secrets.PAT || secrets.GITHUB_TOKEN }} 36 | fetch-depth: 0 37 | 38 | # Collect data & generate markdown 39 | - name: GitHub Dependents Info 40 | uses: nvuillam/github-dependents-info@main 41 | # See documentation for variables details: https://github.com/nvuillam/github-dependents-info?tab=readme-ov-file#%EF%B8%8F-usage 42 | with: 43 | repo: ${{ github.repository }} 44 | # markdownfile: docs/github-dependents-info.md 45 | # badgemarkdownfile: README.md 46 | # sort: stars 47 | # minstars: "0" 48 | env: 49 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 50 | 51 | # Workaround for git issues 52 | - name: Prepare commit 53 | run: sudo chown -R $USER:$USER . 54 | 55 | # Create pull request 56 | - name: Create Pull Request 57 | id: cpr 58 | uses: peter-evans/create-pull-request@v7 59 | with: 60 | token: ${{ secrets.PAT || secrets.GITHUB_TOKEN }} 61 | branch: github-dependents-info-auto-update 62 | commit-message: "[GitHub Dependents Info] Updated markdown file(s)" 63 | delete-branch: true 64 | title: "[GitHub Dependents Info] Updated markdown file" 65 | body: "_Generated with [github-dependents-info](https://github.com/nvuillam/github-dependents-info), by [Nicolas Vuillamy](https://github.com/nvuillam)_" 66 | labels: documentation 67 | - name: Create PR output 68 | run: | 69 | echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}" 70 | echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}" 71 | -------------------------------------------------------------------------------- /.github/workflows/mega-linter.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Mega-Linter GitHub Action configuration file 3 | # More info at https://github.com/oxsecurity/megalinter#readme 4 | name: Mega-Linter 5 | 6 | on: 7 | # Trigger mega-linter at every push. Action will also be visible from Pull Requests to master 8 | push: # Comment this line to trigger action only on pull-requests (not recommended if you don't pay for GH Actions) 9 | pull_request: 10 | branches: [main] 11 | 12 | permissions: read-all 13 | 14 | jobs: 15 | build: 16 | name: Mega-Linter 17 | runs-on: ubuntu-latest 18 | permissions: 19 | # Give the default GITHUB_TOKEN write permission to commit and push, comment issues & post new PR 20 | # Remove the ones you do not need 21 | contents: write 22 | issues: write 23 | pull-requests: write 24 | steps: 25 | # Git Checkout 26 | - name: Checkout Code 27 | uses: actions/checkout@v4 28 | with: 29 | fetch-depth: 0 30 | 31 | # Mega-Linter 32 | - name: Mega-Linter 33 | uses: oxsecurity/megalinter/flavors/cupcake@v8 34 | env: 35 | # All available variables are described in documentation 36 | # https://github.com/oxsecurity/megalinter#configuration 37 | VALIDATE_ALL_CODEBASE: true 38 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 39 | DISABLE_LINTERS: JAVASCRIPT_STANDARD,SPELL_PROSELINT,REPOSITORY_KICS 40 | JAVA_FILTER_REGEX_EXCLUDE: (JavaCallerTester) 41 | 42 | # Upload Mega-Linter artifacts. They will be available on Github action page "Artifacts" section 43 | - name: Archive production artifacts 44 | if: success() || failure() 45 | uses: actions/upload-artifact@v4 46 | with: 47 | name: Mega-Linter reports 48 | path: | 49 | megalinter-reports 50 | mega-linter.log 51 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: [push, pull_request] 4 | 5 | permissions: read-all 6 | 7 | concurrency: 8 | group: ${{ github.ref_name }}-${{ github.workflow }} 9 | cancel-in-progress: true 10 | 11 | jobs: 12 | test: 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | node_version: ['18', '20'] 17 | java_version: ['8', '11', '17', '21'] 18 | java_distrib: [temurin] 19 | os: [ubuntu-latest, macos-latest, windows-latest] 20 | include: 21 | - node_version: '18' 22 | java_version: '17' 23 | java_distrib: adopt 24 | os: ubuntu-latest 25 | exclude: 26 | # excludes node 8 on macOS 27 | - os: macos-latest 28 | java_version: '8' 29 | name: Test 30 | runs-on: ${{ matrix.os }} 31 | timeout-minutes: 15 32 | steps: 33 | - name: Checkout Code 34 | uses: actions/checkout@v4 35 | - name: Install node 36 | uses: actions/setup-node@v4 37 | with: 38 | node-version: ${{ matrix.node_version }} 39 | - name: Install Java 40 | uses: actions/setup-java@v4 41 | with: 42 | distribution: ${{ matrix.java_distrib }} 43 | java-version: ${{ matrix.java_version }} 44 | - name: Install dependencies and link 45 | run: npm ci 46 | - name: Run tests 47 | env: 48 | DEBUG: java-caller,njre 49 | run: npm run test 50 | 51 | coverage: 52 | name: Test - No Java - CodeCov 53 | strategy: 54 | matrix: 55 | debian_version: [bookworm] 56 | node_version: ['18'] 57 | os: [ubuntu-latest] 58 | runs-on: ${{ matrix.os }} 59 | container: 60 | image: "node:${{ matrix.node_version }}-${{ matrix.debian_version }}" 61 | timeout-minutes: 15 62 | steps: 63 | - name: Checkout Code 64 | uses: actions/checkout@v4 65 | - name: Install dependencies and link 66 | run: npm ci 67 | - name: Run tests 68 | env: 69 | DEBUG: "java-caller" 70 | run: npm run test:coverage 71 | - name: Build coverage report 72 | run: ./node_modules/.bin/nyc report --reporter text-lcov > coverage.lcov 73 | - name: Upload coverage to Codecov 74 | uses: codecov/codecov-action@v4 75 | with: 76 | fail_ci_if_error: true 77 | file: coverage.lcov 78 | flags: unittests 79 | token: ${{ secrets.CODECOV_TOKEN }} # required 80 | verbose: true 81 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | node_modules/ 3 | 4 | coverage/ 5 | 6 | .nyc_output/ 7 | 8 | megalinter-reports/ 9 | -------------------------------------------------------------------------------- /.lycheeignore: -------------------------------------------------------------------------------- 1 | # These links are ignored by lychee link checker: https://github.com/lycheeverse/lychee 2 | # The file allows you to list multiple regular expressions for exclusion (one pattern per line). 3 | # The `.lycheeignore` file is only used for excluding URLs, not paths. Use the `exclude_path` key in the `lychee.toml` file. ref: https://github.com/lycheeverse/lycheeverse.github.io/blob/master/recipes/excluding-paths.md 4 | 5 | my-company.com 6 | https://megalinter.io/ 7 | https://megalinter.io/flavors/ 8 | https://megalinter.io/configuration/ 9 | https://www.linkedin.com/ 10 | https://twitter.com 11 | https://twitter.com/intent/tweet 12 | https://fonts.gstatic.com 13 | https://img.shields.io 14 | http://mozilla.org/MPL/2.0/ 15 | https://github.com/sider/goodcheck 16 | https://api.github.com/repos/powershell/powershell/releases 17 | https://storage.googleapis.com/dart-archive/channels/stable/release 18 | https://stylelint.io/user-guide/integrations/other#analysis-platform-engines 19 | https://raw.githubusercontent.com/some_org/some_repo/mega-linter-rules 20 | https://raw.githubusercontent.com/cookiejar/megalinter-plugin-cookiejar/main/cookietemplate.mega-linter-descriptor.yml 21 | https://github.com/oxsecurity/megalinter/raw/main/docs/assets/icons/security.ico 22 | https://github.com/oxsecurity/megalinter/raw/main/docs/assets/icons/swift.ico 23 | https://stylelint.io/user-guide/integrations/other#analysis-platform-engines 24 | https://github.com/pmd/pmd/releases/download/pmd_releases 25 | https://twitter.com/intent/tweet* 26 | circleci/* 27 | https://github.com/* 28 | -------------------------------------------------------------------------------- /.mega-linter.yml: -------------------------------------------------------------------------------- 1 | DISABLE_ERRORS_LINTERS: 2 | - ACTION_ACTIONLINT 3 | FILTER_REGEX_EXCLUDE: (docs\/github-dependents-info\.md|package-lock\.json) 4 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "type": "node", 6 | "request": "attach", 7 | "name": "Attach to Remote", 8 | "address": "127.0.0.1", 9 | "port": 9229, 10 | "smartStep": true, 11 | "skipFiles": [ 12 | "/**" 13 | ] 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## Unreleased 4 | 5 | ## [4.2.1] 2025-05-25 6 | 7 | - Fix to allow absolute path to JAR file 8 | - Upgrade dependencies 9 | 10 | ## [4.2.0] 2025-02-23 11 | 12 | - Upgrade to njre v1.4.2 13 | - Upgrade dependencies 14 | 15 | ## [4.1.1] 2024-08-30 16 | 17 | - Upgrade to njre v1.4.0 18 | - Fix issue when package called from ES Module by using njre installPath option 19 | 20 | ## [4.1.0] 2024-08-20 21 | 22 | - Upgrade to MegaLinter v8 23 | - Upgrade npm dependencies, including base package njre to 1.3.0 24 | 25 | ## [4.0.0] 2024-05-08 26 | 27 | - When java used has been installed by JavaCaller, use full java executable path to perform the calls 28 | - Before 4.00: Update PATH + `java -cp /home/circleci/project/test/java/dist com.nvuillam.javacaller.JavaCallerTester` 29 | - Since 4.0.0: Update PATH + `/home/circleci/.java-caller/jre/jdk-20.0.2+9/bin/java -cp /home/circleci/project/test/java/dist com.nvuillam.javacaller.JavaCallerTester` 30 | - For example handles issue where Java 21 is installed and you need to run Java 17 with JavaCaller 31 | - Refactor CI/CD 32 | - Add additional tests in GitHub Actions 33 | - Test in more contexts (Mac, Java 21...) 34 | - Java 8 and 14 on Mac are not supported: Set default minimum java version to 11 on Mac 35 | 36 | ## [3.3.1] 2024-04-28 37 | 38 | - Upgrade tar dependency to avoid CVE 39 | 40 | ## [3.3.0] 2024-01-29 41 | 42 | - Add option for using javaw instead of java on run for Windows, by [@SotirisVas](https://github.com/SotirisVas) in [#65](https://github.com/nvuillam/node-java-caller/issues/65) 43 | - Add [github-dependents-info](https://github.com/nvuillam/node-java-caller/blob/main/docs/github-dependents-info.md) page and generation 44 | - Update minor dependencies 45 | 46 | ## [3.2.0] 2023-11-26 47 | 48 | - Upgrade njre to v1.1.0 (now handles Mac M1) 49 | 50 | ## [3.1.2] 2023-11-25 51 | 52 | - Add support for configuring windowsVerbatimArguments on run to make it easier to create cross platform compatible code. 53 | 54 | ## [3.1.1] 2023-11-19 55 | 56 | - fix couple of issues in the rule used to detect if desired java version is installed or not, by [@djukxe](https://github.com/djukxe) in [#46](https://github.com/nvuillam/node-java-caller/pull/46) 57 | 58 | ## [3.1.0] 2023-11-18 59 | 60 | - Use semver module to check found java version instead of custom code 61 | - Add java 17 to test cases 62 | - Automate and secure releases using GitHub Actions 63 | - Inclusivity: Rename git branch master into main 64 | 65 | ## [3.0.0] 2023-09-19 66 | 67 | - Upgrade njre to 1.0.0 (Allowing to install until Java 20) 68 | - Upgrade dependencies 69 | 70 | ## [2.7.0] 2022-11-16 71 | 72 | - add stdoutEncoding option (default `utf8`) ([#26](https://github.com/nvuillam/node-java-caller/pull/26), by [danunafig](https://github.com/danunafig)) 73 | 74 | ## [2.6.0] 2022-09-11 75 | 76 | - Fix override of java executable on Linux & Mac environments ([#23](https://github.com/nvuillam/node-java-caller/pull/23)) 77 | - Allow to use `JAVA_CALLER_JAVA_EXECUTABLE` environment variable to force javaExecutable option 78 | - Fix npm audit issues 79 | - Upgrade dependencies 80 | - debug 81 | - eslint 82 | - fs-extra 83 | - mocha 84 | - njre 85 | - nyc 86 | - which 87 | 88 | ## [2.5.0] 2022-08-10 89 | 90 | - Upgrade NPM dependencies 91 | - CI: upgrade to [MegaLinter v6](https://oxsecurity.github.io/megalinter/latest/) 92 | 93 | ## [2.4.0] 2020-07-19 94 | 95 | - Fix additionalJavaArgs issue #13 96 | 97 | ## [2.3.0] 2020-09-05 98 | 99 | - Support absolute paths in classpath with argument `useAbsoluteClassPaths` and classPath as array of strings ([#12](https://github.com/nvuillam/node-java-caller/pull/12), by [Dan Gowans](https://github.com/dangowans)) 100 | 101 | ## [2.2.3] 2020-09-05 102 | 103 | - Fix Java 8 detection ([#101@npm-groovy-lint](https://github.com/nvuillam/npm-groovy-lint/issues/101)) 104 | 105 | ## [2.2.0] 2020-08-29 106 | 107 | - Fix CLASSPATH on windows in case there are spaces in paths 108 | - Update License to MIT 109 | 110 | ## [2.1.0] 2020-08-12 111 | 112 | - Allow to use java-caller to build your own CLI embedding java sources 113 | - Example projects using module and CLI 114 | 115 | ## [2.0.0] 2020-08-11 116 | 117 | - Big refactoring to simplify and enhance performances of code checking/installing java version 118 | - Replace use of deprecated package [node-jre](https://github.com/schreiben/node-jre) by [njre](https://github.com/raftario/njre) 119 | - Compliance with JDK & JRE from 8 to 14 ([AdoptOpenJdk](https://adoptopenjdk.net/) releases) 120 | 121 | ## [1.1.0] 2020-08-10 122 | 123 | - Return `javaChildProcess` when `detached` is true, so it can be used to be killed later 124 | 125 | ## [1.0.0] 2020-08-10 126 | 127 | - Initial version 128 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at nicolas.vuillamy@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are very welcome ! 4 | 5 | Instructions : 6 | 7 | - Fork the repository and clone it on your computer 8 | - Install dependencies: `npm install` 9 | - Update source code and add mocha tests for any code you create 10 | - Run `npm run lint:fix` then `npm run test` to check your updates didn't break anything 11 | - Once your code is ready, documented and tested, please make a [pull request](https://github.com/nvuillam/node-java-caller/pulls) :) 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Nicolas Vuillamy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Java Caller for Node.js 3 | 4 | [![Version](https://img.shields.io/npm/v/java-caller.svg)](https://www.npmjs.com/package/java-caller) 5 | [![Downloads/week](https://img.shields.io/npm/dw/java-caller.svg)](https://npmjs.org/package/java-caller) 6 | [![Downloads/total](https://img.shields.io/npm/dt/java-caller.svg)](https://npmjs.org/package/java-caller) 7 | [![Generated by github-dependents-info](https://img.shields.io/static/v1?label=Used%20by&message=104&color=informational&logo=slickpic)](https://github.com/nvuillam/node-java-caller/blob/main/docs/github-dependents-info.md) 8 | [![CircleCI](https://circleci.com/gh/nvuillam/node-java-caller/tree/master.svg?style=shield)](https://circleci.com/gh/nvuillam/node-java-caller/tree/master) 9 | [![Mega-Linter](https://github.com/nvuillam/node-java-caller/workflows/Mega-Linter/badge.svg)](https://github.com/nvuillam/mega-linter#readme) 10 | [![codecov](https://codecov.io/gh/nvuillam/node-java-caller/branch/master/graph/badge.svg)](https://codecov.io/gh/nvuillam/node-java-caller) 11 | [![GitHub contributors](https://img.shields.io/github/contributors/nvuillam/node-java-caller.svg)](https://gitHub.com/nvuillam/node-java-caller/graphs/contributors/) 12 | [![GitHub stars](https://img.shields.io/github/stars/nvuillam/node-java-caller?label=Star&maxAge=2592000)](https://GitHub.com/nvuillam/node-java-caller/stargazers/) 13 | [![License](https://img.shields.io/npm/l/java-caller.svg)](https://github.com/nvuillam/node-java-caller/blob/master/LICENSE) 14 | [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) 15 | 16 | Lightweight cross-platform javascript module to **easily call java commands from Node.js sources**. 17 | 18 | - **Automatically installs required Java version** if not present on the system 19 | - Compliant with **JDK & JRE** from **8 to 21** 20 | - Uses node [spawn](https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options) method to perform the call 21 | 22 | There are two ways to use java-caller: 23 | 24 | - **module**: Manually call JavaCaller in your custom JS/TS code ([example project](https://github.com/nvuillam/node-java-caller/tree/master/examples/module_app)) 25 | - **CLI**: Just define a java-caller-config.json and you can deliver your java executables as your own NPM packages ! ([example project](https://github.com/nvuillam/node-java-caller/tree/master/examples/cli_app), which can be used as starter kit) 26 | 27 | ## Installation 28 | 29 | ```shell 30 | npm install java-caller --save 31 | ``` 32 | 33 | ## Usage 34 | 35 | ```javascript 36 | const JavaCaller = require('java-caller'); 37 | const java = new JavaCaller(JAVA_CALLER_OPTIONS); 38 | const {status, stdout, stderr} = await java.run(JAVA_ARGUMENTS,JAVA_CALLER_RUN_OPTIONS); 39 | ``` 40 | 41 | ### JAVA_CALLER_OPTIONS 42 | 43 | | Parameter | Description | Default value | Example | 44 | | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- | ---------------------------------------- | 45 | | jar | Path to executable jar file | | `"myfolder/myjar.jar"` | 46 | | classPath | If jar parameter is not set, classpath to use
Use `:` as separator (it will be converted if runned on Windows), or use a string array. | `.` (current folder) | `"java/myJar.jar:java/myOtherJar.jar"` | 47 | | useAbsoluteClassPaths | Set to true if classpaths should not be based on the rootPath | `false` | `true` | 48 | | mainClass | If classPath set, main class to call | | `"com.example.MyClass"` | 49 | | rootPath | If classPath elements are not relative to the current folder, you can define a root path.
You may use `__dirname` if you classes / jars are in your module folder | `.` (current folder) | `"/home/my/folder/containing/jars"` | 50 | | minimumJavaVersion | Minimum java version to be used to call java command.
If the java version found on machine is lower, java-caller will try to install and use the appropriate one | `8` | `11` | 51 | | maximumJavaVersion | Maximum java version to be used to call java command.
If the java version found on machine is upper, java-caller will try to install and use the appropriate one
Can be equal to minimumJavaVersion | | `10` | 52 | | javaType | jre or jdk (if not defined and installation is required, jre will be installed) | | `"jre"` | 53 | | additionalJavaArgs | Additional parameters for JVM that will be added in every JavaCaller instance runs | | `["-Xms256m","-Xmx2048m"]` | 54 | | javaExecutable | You can force to use a defined java executable, instead of letting java-caller find/install one. Can also be defined with env var `JAVA_CALLER_JAVA_EXECUTABLE` | | `"/home/some-java-version/bin/java.exe"` | 55 | 56 | ### JAVA_ARGUMENTS 57 | 58 | The list of arguments can contain both arguments types together: 59 | 60 | - Java arguments (**-X***, **-D***). ex: `"-Xms256m"`, `"-Xmx2048m"` 61 | - Main class arguments (sent to `public static void main method`). ex: `"--someflag"` , `"--someflagwithvalue myVal"` , `"-c"` 62 | 63 | Example: `["-Xms256m", "--someflagwithvalue myVal", "-c"]` 64 | 65 | ### JAVA_CALLER_RUN_OPTIONS 66 | 67 | | Parameter | Description | Default | Example | 68 | |-----------|-------------|---------|---------| 69 | | [detached](https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options) | If set to true, node will node wait for the java command to be completed.
In that case, `childJavaProcess` property will be returned, but `stdout` and `stderr` may be empty, except if an error is triggered at command execution | `false` | `true` 70 | | [stdoutEncoding](https://nodejs.org/api/stream.html#readablesetencodingencoding) | Adds control on spawn process stdout | `utf8` | `ucs2` | 71 | | waitForErrorMs | If detached is true, number of milliseconds to wait to detect an error before exiting JavaCaller run | `500` | `2000` | 72 | | [cwd](https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options) | You can override cwd of spawn called by JavaCaller runner | `process.cwd()` | `some/other/cwd/folder` | 73 | | javaArgs | List of arguments for JVM only, not the JAR or the class | `[]` | `['--add-opens=java.base/java.lang=ALL-UNNAMED']` | 74 | | [windowsVerbatimArguments](https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options) | No quoting or escaping of arguments is done on Windows. Ignored on Unix. This is set to true automatically when shell is specified and is CMD. | `true` | `false` | 75 | | [windowless](https://docs.oracle.com/en/java/javase/17/docs/specs/man/java.html#:~:text=main()%20method.-,javaw,information%20if%20a%20launch%20fails.) | If windowless is true, JavaCaller calls javaw instead of java to not create any windows, useful when using detached on Windows. Ignored on Unix. | false | true 76 | 77 | ## Examples 78 | 79 | Call a class located in classpath 80 | 81 | ```javascript 82 | const java = new JavaCaller({ 83 | classPath: 'test/java/dist', 84 | mainClass: 'com.nvuillam.javacaller.JavaCallerTester' 85 | }); 86 | const { status, stdout, stderr } = await java.run(); 87 | ``` 88 | 89 | Call a class with multiple folders in the classPath 90 | 91 | ```javascript 92 | const java = new JavaCaller({ 93 | classPath: ['C:\\pathA\\test\\java\\dist', 'C:\\pathB\\test\\java\\dist'], 94 | mainClass: 'com.nvuillam.javacaller.JavaCallerTester' 95 | }); 96 | const { status, stdout, stderr } = await java.run(); 97 | ``` 98 | 99 | Call a class located in classpath with java and custom arguments 100 | 101 | ```javascript 102 | const java = new JavaCaller({ 103 | classPath: 'test/java/dist', 104 | mainClass: 'com.nvuillam.javacaller.JavaCallerTester' 105 | }); 106 | const { status, stdout, stderr } = await java.run(['-Xms256m', '-Xmx2048m', '--customarg nico']); 107 | ``` 108 | 109 | Call a class in jar located in classpath 110 | 111 | ```javascript 112 | const java = new JavaCaller({ 113 | classPath: 'test/java/jar/JavaCallerTester.jar', 114 | mainClass: 'com.nvuillam.javacaller.JavaCallerTester' 115 | }); 116 | const { status, stdout, stderr } = await java.run(); 117 | ``` 118 | 119 | Call a runnable jar 120 | 121 | ```javascript 122 | const java = new JavaCaller({ 123 | jar: 'test/java/jar/JavaCallerTesterRunnable.jar', 124 | }); 125 | const { status, stdout, stderr } = await java.run(); 126 | ``` 127 | 128 | Call a detached java process 129 | 130 | ```javascript 131 | const java = new JavaCaller({ 132 | classPath: 'test/java/dist', 133 | mainClass: 'com.nvuillam.javacaller.JavaCallerTester' 134 | }); 135 | const { status, stdout, stderr, childJavaProcess } = await java.run(['--sleep'], { detached: true }); 136 | 137 | // Kill later the java process if necessary 138 | childJavaProcess.kill('SIGINT'); 139 | ``` 140 | 141 | Call a windowless java process 142 | 143 | ```javascript 144 | const java = new JavaCaller({ 145 | classPath: 'test/java/dist', 146 | mainClass: 'com.nvuillam.javacaller.JavaCallerTester' 147 | }); 148 | const { status, stdout, stderr } = await java.run(['--sleep'], { windowless: true }); 149 | ``` 150 | 151 | You can see **more examples in** [**test methods**](https://github.com/nvuillam/node-java-caller/blob/master/test/java-caller.test.js) 152 | 153 | ## TROUBLESHOOTING 154 | 155 | Set environment variable `DEBUG=java-caller` before calling your code using java-caller module, and you will see the java commands executed. 156 | 157 | Example debug log: 158 | 159 | ```shell 160 | java-caller Found Java version 1.80131 +1s 161 | java-caller Java command: java -Xms256m -Xmx2048m -cp C:\Work\gitPerso\node-java-caller\test\java\dist com.nvuillam.javacaller.JavaCallerTester -customarg nico +1ms 162 | ``` 163 | 164 | ## CONTRIBUTE 165 | 166 | Contributions are very welcome ! 167 | 168 | Please follow [Contribution instructions](CONTRIBUTING.md) 169 | 170 | ## RELEASE NOTES 171 | 172 | See complete [CHANGELOG](CHANGELOG.md) 173 | -------------------------------------------------------------------------------- /docs/github-dependents-info.md: -------------------------------------------------------------------------------- 1 | # Dependents stats for nvuillam/node-java-caller 2 | 3 | [![Generated by github-dependents-info](https://img.shields.io/static/v1?label=Used%20by&message=104&color=informational&logo=slickpic)](https://github.com/nvuillam/node-java-caller/network/dependents) 4 | [![Generated by github-dependents-info](https://img.shields.io/static/v1?label=Used%20by%20(public)&message=104&color=informational&logo=slickpic)](https://github.com/nvuillam/node-java-caller/network/dependents) 5 | [![Generated by github-dependents-info](https://img.shields.io/static/v1?label=Used%20by%20(private)&message=-104&color=informational&logo=slickpic)](https://github.com/nvuillam/node-java-caller/network/dependents) 6 | [![Generated by github-dependents-info](https://img.shields.io/static/v1?label=Used%20by%20(stars)&message=407&color=informational&logo=slickpic)](https://github.com/nvuillam/node-java-caller/network/dependents) 7 | 8 | | Repository | Stars | 9 | | :-------- | -----: | 10 | |   [Checkmk](https://github.com/Checkmk) / [checkmk](https://github.com/Checkmk/checkmk) | 1833 | 11 | |   [nvuillam](https://github.com/nvuillam) / [npm-groovy-lint](https://github.com/nvuillam/npm-groovy-lint) | 221 | 12 | |   [nvuillam](https://github.com/nvuillam) / [vscode-groovy-lint](https://github.com/nvuillam/vscode-groovy-lint) | 77 | 13 | |   [oslabs-beta](https://github.com/oslabs-beta) / [saamsa](https://github.com/oslabs-beta/saamsa) | 49 | 14 | |   [nvuillam](https://github.com/nvuillam) / [node-java-caller](https://github.com/nvuillam/node-java-caller) | 42 | 15 | |   [andreialecu](https://github.com/andreialecu) / [yarn-cache-remover](https://github.com/andreialecu/yarn-cache-remover) | 7 | 16 | |   [cityssm](https://github.com/cityssm) / [corporate-records-manager](https://github.com/cityssm/corporate-records-manager) | 6 | 17 | |   [docupike](https://github.com/docupike) / [docs](https://github.com/docupike/docs) | 5 | 18 | |   [BoilerTime](https://github.com/BoilerTime) / [boilertime](https://github.com/BoilerTime/boilertime) | 5 | 19 | |   [cityssm](https://github.com/cityssm) / [contract-expiration-tracker](https://github.com/cityssm/contract-expiration-tracker) | 3 | 20 | |   [aboe026](https://github.com/aboe026) / [software-update-checker](https://github.com/aboe026/software-update-checker) | 3 | 21 | |   [megaacheyounes](https://github.com/megaacheyounes) / [Bananalyzer](https://github.com/megaacheyounes/Bananalyzer) | 3 | 22 | |   [cityssm](https://github.com/cityssm) / [node-docushare](https://github.com/cityssm/node-docushare) | 3 | 23 | |   [renuTester](https://github.com/renuTester) / [todomvc](https://github.com/renuTester/todomvc) | 1 | 24 | |   [sunnybeta](https://github.com/sunnybeta) / [calc](https://github.com/sunnybeta/calc) | 1 | 25 | |   [CHUGGU-ME](https://github.com/CHUGGU-ME) / [CHUGGU-ME-v2](https://github.com/CHUGGU-ME/CHUGGU-ME-v2) | 1 | 26 | |   [Moaaz-Adel](https://github.com/Moaaz-Adel) / [automation-exercise-cypress](https://github.com/Moaaz-Adel/automation-exercise-cypress) | 1 | 27 | |   [aliaks-ei](https://github.com/aliaks-ei) / [truck-configurator](https://github.com/aliaks-ei/truck-configurator) | 1 | 28 | |   [gorkemkaramolla](https://github.com/gorkemkaramolla) / [Java-Project-13-06-2023-Maribor-University-Slovenia](https://github.com/gorkemkaramolla/Java-Project-13-06-2023-Maribor-University-Slovenia) | 1 | 29 | |   [RebelTat](https://github.com/RebelTat) / [megalinter](https://github.com/RebelTat/megalinter) | 1 | 30 | |   [bnorthern42](https://github.com/bnorthern42) / [search-pdf-regex](https://github.com/bnorthern42/search-pdf-regex) | 1 | 31 | |   [jcroall](https://github.com/jcroall) / [polaris-report-action](https://github.com/jcroall/polaris-report-action) | 1 | 32 | |   [aboe026](https://github.com/aboe026) / [shields.io-badge-results](https://github.com/aboe026/shields.io-badge-results) | 1 | 33 | |   [dxworks](https://github.com/dxworks) / [inspector-git](https://github.com/dxworks/inspector-git) | 1 | 34 | |   [cityssm](https://github.com/cityssm) / [contractor-prequal-system](https://github.com/cityssm/contractor-prequal-system) | 1 | 35 | |   [Sarves14](https://github.com/Sarves14) / [PHR-CPABE](https://github.com/Sarves14/PHR-CPABE) | 1 | 36 | |   [JsusAyola](https://github.com/JsusAyola) / [OfLovePawPritns](https://github.com/JsusAyola/OfLovePawPritns) | 0 | 37 | |   [JsusAyola](https://github.com/JsusAyola) / [Paw-Prints-Of-Love](https://github.com/JsusAyola/Paw-Prints-Of-Love) | 0 | 38 | |   [AbhishekS-jft](https://github.com/AbhishekS-jft) / [Scrapping-Data--JavaTpoint](https://github.com/AbhishekS-jft/Scrapping-Data--JavaTpoint) | 0 | 39 | |   [artem1000](https://github.com/artem1000) / [nvim-config](https://github.com/artem1000/nvim-config) | 0 | 40 | |   [seilorjunior](https://github.com/seilorjunior) / [megalinter](https://github.com/seilorjunior/megalinter) | 0 | 41 | |   [nexiss](https://github.com/nexiss) / [pdf-tools](https://github.com/nexiss/pdf-tools) | 0 | 42 | |   [kyvong123](https://github.com/kyvong123) / [WebTruongDaiHoc-Reactjs-ExpressJs](https://github.com/kyvong123/WebTruongDaiHoc-Reactjs-ExpressJs) | 0 | 43 | |   [mmottl](https://github.com/mmottl) / [megalinter](https://github.com/mmottl/megalinter) | 0 | 44 | |   [saivenkat2001](https://github.com/saivenkat2001) / [groovy_lint](https://github.com/saivenkat2001/groovy_lint) | 0 | 45 | |   [jatut](https://github.com/jatut) / [my_checkmk](https://github.com/jatut/my_checkmk) | 0 | 46 | |   [rtyner](https://github.com/rtyner) / [dotfiles](https://github.com/rtyner/dotfiles) | 0 | 47 | |   [acpcreation](https://github.com/acpcreation) / [Evaluation-Examples](https://github.com/acpcreation/Evaluation-Examples) | 0 | 48 | |   [mywork-dragon](https://github.com/mywork-dragon) / [casual_website](https://github.com/mywork-dragon/casual_website) | 0 | 49 | |   [GitTiagoOliveira](https://github.com/GitTiagoOliveira) / [checkmk](https://github.com/GitTiagoOliveira/checkmk) | 0 | 50 | |   [GCbeheo](https://github.com/GCbeheo) / [TrueShort-npm-groovy-lint](https://github.com/GCbeheo/TrueShort-npm-groovy-lint) | 0 | 51 | |   [tysontrinh-tru](https://github.com/tysontrinh-tru) / [npm-groovy-lint](https://github.com/tysontrinh-tru/npm-groovy-lint) | 0 | 52 | |   [YoutacRandS-VA](https://github.com/YoutacRandS-VA) / [npm-groovy-lint](https://github.com/YoutacRandS-VA/npm-groovy-lint) | 0 | 53 | |   [Swedish-Coffee-House](https://github.com/Swedish-Coffee-House) / [zd-3022129](https://github.com/Swedish-Coffee-House/zd-3022129) | 0 | 54 | |   [fabstock](https://github.com/fabstock) / [jenkins-nodetest-cicd](https://github.com/fabstock/jenkins-nodetest-cicd) | 0 | 55 | |   [Deathblood69](https://github.com/Deathblood69) / [magasin-back](https://github.com/Deathblood69/magasin-back) | 0 | 56 | |   [TrueShort](https://github.com/TrueShort) / [npm-groovy-lint](https://github.com/TrueShort/npm-groovy-lint) | 0 | 57 | |   [Moaaz-Adel](https://github.com/Moaaz-Adel) / [Jobsity-Challenge](https://github.com/Moaaz-Adel/Jobsity-Challenge) | 0 | 58 | |   [takutokishioka](https://github.com/takutokishioka) / [groovy-lint-playground](https://github.com/takutokishioka/groovy-lint-playground) | 0 | 59 | |   [gkumarcertinia](https://github.com/gkumarcertinia) / [test](https://github.com/gkumarcertinia/test) | 0 | 60 | |   [bdm112](https://github.com/bdm112) / [nni-volk-po](https://github.com/bdm112/nni-volk-po) | 0 | 61 | |   [bdm112](https://github.com/bdm112) / [nnx-felg-cut](https://github.com/bdm112/nnx-felg-cut) | 0 | 62 | |   [bdm112](https://github.com/bdm112) / [nnl-fux-90](https://github.com/bdm112/nnl-fux-90) | 0 | 63 | |   [bdm112](https://github.com/bdm112) / [xxi-datatest](https://github.com/bdm112/xxi-datatest) | 0 | 64 | |   [bdm112](https://github.com/bdm112) / [open-gopad](https://github.com/bdm112/open-gopad) | 0 | 65 | |   [fevrin](https://github.com/fevrin) / [megalinter](https://github.com/fevrin/megalinter) | 0 | 66 | |   [cut-dicl](https://github.com/cut-dicl) / [ditis-ui](https://github.com/cut-dicl/ditis-ui) | 0 | 67 | |   [zedomel](https://github.com/zedomel) / [nodejs-nomer](https://github.com/zedomel/nodejs-nomer) | 0 | 68 | |   [SamueleMaroli](https://github.com/SamueleMaroli) / [groovy-work](https://github.com/SamueleMaroli/groovy-work) | 0 | 69 | |   [iliedorobat](https://github.com/iliedorobat) / [QoLI-Map-Service](https://github.com/iliedorobat/QoLI-Map-Service) | 0 | 70 | |   [echoix](https://github.com/echoix) / [npm-groovy-lint](https://github.com/echoix/npm-groovy-lint) | 0 | 71 | |   [yoolinkaa](https://github.com/yoolinkaa) / [Flower](https://github.com/yoolinkaa/Flower) | 0 | 72 | |   [dxworks](https://github.com/dxworks) / [jafax](https://github.com/dxworks/jafax) | 0 | 73 | |   [aboe026](https://github.com/aboe026) / [release-node-project](https://github.com/aboe026/release-node-project) | 0 | 74 | |   [rasa](https://github.com/rasa) / [megalinter](https://github.com/rasa/megalinter) | 0 | 75 | |   [Souliyakv](https://github.com/Souliyakv) / [vending-server-main](https://github.com/Souliyakv/vending-server-main) | 0 | 76 | |   [andrewvaughan](https://github.com/andrewvaughan) / [megalinter](https://github.com/andrewvaughan/megalinter) | 0 | 77 | |   [0xshimon](https://github.com/0xshimon) / [megalinter](https://github.com/0xshimon/megalinter) | 0 | 78 | |   [BrainsoftGIt](https://github.com/BrainsoftGIt) / [Lumaguita](https://github.com/BrainsoftGIt/Lumaguita) | 0 | 79 | |   [aboe026](https://github.com/aboe026) / [node-update-dependencies](https://github.com/aboe026/node-update-dependencies) | 0 | 80 | |   [burhan-sancakli](https://github.com/burhan-sancakli) / [java_employee_manager](https://github.com/burhan-sancakli/java_employee_manager) | 0 | 81 | |   [arunnalladi](https://github.com/arunnalladi) / [megalinter](https://github.com/arunnalladi/megalinter) | 0 | 82 | |   [arunnalladii](https://github.com/arunnalladii) / [ox-security](https://github.com/arunnalladii/ox-security) | 0 | 83 | |   [sarvex](https://github.com/sarvex) / [megalinter](https://github.com/sarvex/megalinter) | 0 | 84 | |   [katalon-labs](https://github.com/katalon-labs) / [katalon-chrome-recorder](https://github.com/katalon-labs/katalon-chrome-recorder) | 0 | 85 | |   [4Hasham](https://github.com/4Hasham) / [TOGAPI](https://github.com/4Hasham/TOGAPI) | 0 | 86 | |   [0fatal](https://github.com/0fatal) / [node-bfg](https://github.com/0fatal/node-bfg) | 0 | 87 | |   [actions-marketplace-validations](https://github.com/actions-marketplace-validations) / [oxsecurity_megalinter](https://github.com/actions-marketplace-validations/oxsecurity_megalinter) | 0 | 88 | |   [rohangt1](https://github.com/rohangt1) / [ADSampleRepo](https://github.com/rohangt1/ADSampleRepo) | 0 | 89 | |   [mashafrancis](https://github.com/mashafrancis) / [sa-jenkins](https://github.com/mashafrancis/sa-jenkins) | 0 | 90 | |   [designneexx](https://github.com/designneexx) / [minecraft-server](https://github.com/designneexx/minecraft-server) | 0 | 91 | |   [designneexx](https://github.com/designneexx) / [mcdsxserver](https://github.com/designneexx/mcdsxserver) | 0 | 92 | |   [katalon-labs](https://github.com/katalon-labs) / [katalon-recorder-extension](https://github.com/katalon-labs/katalon-recorder-extension) | 0 | 93 | |   [rohangt1](https://github.com/rohangt1) / [NodeAuditAppAWS](https://github.com/rohangt1/NodeAuditAppAWS) | 0 | 94 | |   [koshmack](https://github.com/koshmack) / [gitlab-ci-node](https://github.com/koshmack/gitlab-ci-node) | 0 | 95 | |   [dxworks](https://github.com/dxworks) / [Report-Generator-Wrapper](https://github.com/dxworks/Report-Generator-Wrapper) | 0 | 96 | |   [vilher](https://github.com/vilher) / [quiz](https://github.com/vilher/quiz) | 0 | 97 | |   [viktolim](https://github.com/viktolim) / [SaitynoProject](https://github.com/viktolim/SaitynoProject) | 0 | 98 | |   [carmellino](https://github.com/carmellino) / [BoilingWater](https://github.com/carmellino/BoilingWater) | 0 | 99 | |   [rohangt1](https://github.com/rohangt1) / [Node](https://github.com/rohangt1/Node) | 0 | 100 | |   [jcroall](https://github.com/jcroall) / [synopsys-sig-node](https://github.com/jcroall/synopsys-sig-node) | 0 | 101 | |   [dxworks](https://github.com/dxworks) / [report-generator](https://github.com/dxworks/report-generator) | 0 | 102 | |   [ppasszzw311](https://github.com/ppasszzw311) / [nutmeg_a](https://github.com/ppasszzw311/nutmeg_a) | 0 | 103 | |   [stevengonsalvez](https://github.com/stevengonsalvez) / [megalinter](https://github.com/stevengonsalvez/megalinter) | 0 | 104 | |   [dxworks](https://github.com/dxworks) / [overview-tables](https://github.com/dxworks/overview-tables) | 0 | 105 | |   [aboe026](https://github.com/aboe026) / [data-structures](https://github.com/aboe026/data-structures) | 0 | 106 | |   [dxworks](https://github.com/dxworks) / [depminer](https://github.com/dxworks/depminer) | 0 | 107 | |   [CausalLabs](https://github.com/CausalLabs) / [sandbox](https://github.com/CausalLabs/sandbox) | 0 | 108 | |   [dxworks](https://github.com/dxworks) / [insider](https://github.com/dxworks/insider) | 0 | 109 | |   [NOUIY](https://github.com/NOUIY) / [npm-groovy-lint](https://github.com/NOUIY/npm-groovy-lint) | 0 | 110 | |   [CausalLabs](https://github.com/CausalLabs) / [examples](https://github.com/CausalLabs/examples) | 0 | 111 | |   [devload](https://github.com/devload) / [node2proguard](https://github.com/devload/node2proguard) | 0 | 112 | |   [RinceLagger](https://github.com/RinceLagger) / [ipog_backend](https://github.com/RinceLagger/ipog_backend) | 0 | 113 | |   [JohnWu966](https://github.com/JohnWu966) / [Image-Reconstruction](https://github.com/JohnWu966/Image-Reconstruction) | 0 | 114 | 115 | _Generated using [github-dependents-info](https://github.com/nvuillam/github-dependents-info), by [Nicolas Vuillamy](https://github.com/nvuillam)_ -------------------------------------------------------------------------------- /examples/cli_app/README.md: -------------------------------------------------------------------------------- 1 | # JavaCaller CLI example 2 | 3 | ## See it in action 4 | 5 | Run the following commands : 6 | 7 | - `npm run install-local-cli` 8 | - `npm run run:cli:verbose` 9 | 10 | ## Use this folder as a starter project 11 | 12 | Please follow these simple instructions 13 | 14 | - Copy your jars/classes in folder `java` 15 | - Update `java-caller-config.json` with the appropriate [JavaCaller options](https://github.com/nvuillam/node-java-caller#java_caller_options) 16 | - Update `package.json`: `name`, `bin`, `scripts` 17 | - Publish your package to npm :) 18 | 19 | Any question ? Please ask in [Issues](https://github.com/nvuillam/node-java-caller/issues) :) 20 | -------------------------------------------------------------------------------- /examples/cli_app/lib/index.js: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env node 2 | "use strict" 3 | 4 | /* 5 | This file does not need to be updated, only java-caller-config.json must be ! 6 | */ 7 | 8 | const { JavaCallerCli } = require("java-caller"); 9 | 10 | // Run asynchronously to use the returned status for process.exit 11 | (async () => { 12 | await new JavaCallerCli(__dirname).process(); 13 | })(); 14 | -------------------------------------------------------------------------------- /examples/cli_app/lib/java-caller-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "classPath": "java/JavaCallerTester.jar", 3 | "mainClass": "com.nvuillam.javacaller.JavaCallerTester", 4 | "minimumJavaVersion": 10 5 | } -------------------------------------------------------------------------------- /examples/cli_app/lib/java/JavaCallerTester.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nvuillam/node-java-caller/dd41cf16a7df82e386f0b66dc312cb3e6105d2c3/examples/cli_app/lib/java/JavaCallerTester.jar -------------------------------------------------------------------------------- /examples/cli_app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "java-caller-example-cli", 3 | "version": "1.0.0", 4 | "description": "Example of project using java-caller as a cli with java-caller-config.json config file", 5 | "main": "lib/index.js", 6 | "files": [ 7 | "lib" 8 | ], 9 | "bin": { 10 | "java-caller-example-cli": "lib/index.js" 11 | }, 12 | "scripts": { 13 | "install-local-cli": "npm install && npm link --force", 14 | "run:source": "node lib/index.js -a list --of arguments", 15 | "run:source:verbose": "env DEBUG=java-caller node lib/index.js -a list --of arguments", 16 | "run:cli": "java-caller-example-cli -a list --of arguments", 17 | "run:verbose": "env DEBUG=java-caller java-caller-example-cli -a list --of arguments" 18 | }, 19 | "keywords": [ 20 | "java-caller", 21 | "example", 22 | "cli", 23 | "manual" 24 | ], 25 | "author": "Nicolas Vuillamy", 26 | "license": "MIT", 27 | "dependencies": { 28 | "java-caller": "^2.1.0" 29 | } 30 | } -------------------------------------------------------------------------------- /examples/module_app/lib/index.js: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env node 2 | "use strict" 3 | 4 | const { JavaCaller } = require("java-caller"); 5 | 6 | // Run asynchronously to use the returned status for process.exit 7 | (async () => { 8 | try { 9 | await runExample(); 10 | } catch (err) { 11 | console.error("Unexpected error: " + err.message + "\n" + err.stack); 12 | process.exitCode = 1; 13 | } 14 | })(); 15 | 16 | // Example function 17 | async function runExample() { 18 | console.log('Welcome to Java Caller example\n'); 19 | console.log(`Let's use java-caller as a module !`); 20 | 21 | const java = new JavaCaller({ 22 | classPath: 'java/JavaCallerTester.jar', // CLASSPATH referencing the package embedded jar files 23 | mainClass: 'com.nvuillam.javacaller.JavaCallerTester',// Main class to call, must be available from CLASSPATH, 24 | rootPath: __dirname, 25 | minimumJavaVersion: 10 26 | }); 27 | const { status, stdout, stderr } = await java.run(['-a', 'list', '--of', 'arguments']); 28 | 29 | console.log(`The status code returned by java command is ${status}`); 30 | if (stdout) { 31 | console.log('stdout of the java command is :\n' + stdout); 32 | } 33 | if (stderr) { 34 | console.log('stderr of the java command is :\n' + stderr); 35 | } 36 | 37 | console.log("Now we can get back on the rest of our custom module code :)") 38 | } -------------------------------------------------------------------------------- /examples/module_app/lib/java/JavaCallerTester.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nvuillam/node-java-caller/dd41cf16a7df82e386f0b66dc312cb3e6105d2c3/examples/module_app/lib/java/JavaCallerTester.jar -------------------------------------------------------------------------------- /examples/module_app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "java-caller-example-module", 3 | "version": "1.0.0", 4 | "description": "Example of project using java-caller as a module", 5 | "main": "lib/index.js", 6 | "files": [ 7 | "lib" 8 | ], 9 | "bin": { 10 | "java-caller-example-module": "lib/index.js" 11 | }, 12 | "scripts": { 13 | "install-local-cli": "npm install && npm link --force", 14 | "run:source": "node lib/index.js", 15 | "run:source:verbose": "env DEBUG=java-caller node lib/index.js", 16 | "run:cli": "java-caller-example-module", 17 | "run:cli:verbose": "env DEBUG=java-caller java-caller-example-module", 18 | "test": "echo \"I strongly encourage you to implement test cases and code coverage, with mocha and nyc for example :)\"" 19 | }, 20 | "keywords": [ 21 | "java-caller", 22 | "example", 23 | "module", 24 | "manual" 25 | ], 26 | "author": "Nicolas Vuillamy", 27 | "license": "MIT", 28 | "dependencies": { 29 | "java-caller": "^2.1.0" 30 | } 31 | } -------------------------------------------------------------------------------- /lib/cli.js: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env node 2 | const { JavaCaller } = require("./java-caller"); 3 | const fse = require("fs-extra"); 4 | const path = require("path"); 5 | 6 | class JavaCallerCli { 7 | "use strict"; 8 | 9 | javaCallerOptions; 10 | 11 | constructor(baseDir) { 12 | // Use user-defined JSON file to read configuration 13 | const configFile = path.resolve(`${baseDir}/java-caller-config.json`); 14 | const options = fse.readJSONSync(configFile); 15 | // Default output is console with CLI 16 | if (options.output == null) { 17 | options.output = "console"; 18 | } 19 | if (options.rootPath == null) { 20 | options.rootPath = baseDir; 21 | } 22 | this.javaCallerOptions = options; 23 | } 24 | 25 | async process() { 26 | const java = new JavaCaller(this.javaCallerOptions); 27 | const args = [...process.argv]; 28 | args.splice(0, 2); 29 | const { status } = await java.run(args); 30 | process.exitCode = status; 31 | } 32 | } 33 | 34 | module.exports = { JavaCallerCli }; 35 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env node 2 | "use strict"; 3 | 4 | const { JavaCaller } = require("./java-caller"); 5 | const { JavaCallerCli } = require("./cli"); 6 | 7 | module.exports = { JavaCaller, JavaCallerCli }; 8 | -------------------------------------------------------------------------------- /lib/java-caller.js: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env node 2 | const debug = require("debug")("java-caller"); 3 | const fse = require("fs-extra"); 4 | const os = require("os"); 5 | const path = require("path"); 6 | const { spawn } = require("child_process"); 7 | const util = require("util"); 8 | const execPromise = util.promisify(require("child_process").exec); 9 | const semver = require("semver"); 10 | 11 | class JavaCaller { 12 | "use strict"; 13 | minimumJavaVersion = os.platform() === "darwin" ? 11 : 8; // Mac starts at 11 14 | maximumJavaVersion; 15 | javaType; 16 | rootPath = "."; 17 | 18 | jar; 19 | classPath = "."; 20 | useAbsoluteClassPaths = false; 21 | mainClass; 22 | output = "none"; // can be none or console 23 | status = null; 24 | 25 | javaSupportDir; 26 | javaExecutable = "java"; 27 | javaExecutableWindowless = "javaw"; 28 | additionalJavaArgs = []; 29 | commandJavaArgs = []; 30 | 31 | javaHome; 32 | javaBin; 33 | javaExecutableFromNodeJavaCaller; 34 | 35 | prevPath; 36 | prevJavaHome; 37 | 38 | /** 39 | * Creates a JavaCaller instance 40 | * @param {object} [opts] - Run options 41 | * @param {string} [opts.jar] - Path to executable jar file 42 | * @param {string | string[]} [opts.classPath] - If jar parameter is not set, classpath to use. Use : as separator (it will be converted if runned on Windows), or use a string array 43 | * @param {boolean} [opts.useAbsoluteClassPaths] - Set to true if classpaths should not be based on the rootPath 44 | * @param {string} [opts.mainClass] - If classPath set, main class to call 45 | * @param {number} [opts.minimumJavaVersion] - Minimum java version to be used to call java command. If the java version found on machine is lower, java-caller will try to install and use the appropriate one 46 | * @param {number} [opts.maximumJavaVersion] - Maximum java version to be used to call java command. If the java version found on machine is upper, java-caller will try to install and use the appropriate one 47 | * @param {string} [opts.javaType] - jre or jdk (if not defined and installation is required, jre will be installed) 48 | * @param {string} [opts.rootPath] - If classPath elements are not relative to the current folder, you can define a root path. You may use __dirname if you classes / jars are in your module folder 49 | * @param {string} [opts.javaExecutable] - You can force to use a defined java executable, instead of letting java-caller find/install one 50 | * @param {string} [opts.additionalJavaArgs] - Additional parameters for JVM that will be added in every JavaCaller instance runs 51 | */ 52 | constructor(opts) { 53 | this.jar = opts.jar || this.jar; 54 | this.classPath = opts.classPath || this.classPath; 55 | this.useAbsoluteClassPaths = opts.useAbsoluteClassPaths || this.useAbsoluteClassPaths; 56 | this.mainClass = opts.mainClass || this.mainClass; 57 | this.minimumJavaVersion = opts.minimumJavaVersion || this.minimumJavaVersion; 58 | this.maximumJavaVersion = opts.maximumJavaVersion || this.maximumJavaVersion; 59 | this.javaType = opts.javaType || this.javaType; 60 | this.rootPath = opts.rootPath || this.rootPath; 61 | this.javaCallerSupportDir = `${os.homedir() + path.sep}.java-caller`; 62 | this.javaExecutable = opts.javaExecutable || process.env.JAVA_CALLER_JAVA_EXECUTABLE || this.javaExecutable; 63 | this.javaExecutableFromNodeJavaCaller = null; 64 | this.additionalJavaArgs = opts.additionalJavaArgs || this.additionalJavaArgs; 65 | this.output = opts.output || this.output; 66 | } 67 | 68 | /** 69 | * Runs java command of a JavaCaller instance 70 | * @param {string[]} [userArguments] - Java command line arguments 71 | * @param {object} [runOptions] - Run options 72 | * @param {boolean} [runOptions.detached = false] - If set to true, node will node wait for the java command to be completed. In that case, childJavaProcess property will be returned, but stdout and stderr may be empty 73 | * @param {string} [runOptions.stdoutEncoding = 'utf8'] - Adds control on spawn process stdout 74 | * @param {number} [runOptions.waitForErrorMs = 500] - If detached is true, number of milliseconds to wait to detect an error before exiting JavaCaller run 75 | * @param {string} [runOptions.cwd = .] - You can override cwd of spawn called by JavaCaller runner 76 | * @param {string} [runOptions.javaArgs = []] - You can override cwd of spawn called by JavaCaller runner 77 | * @param {string} [runOptions.windowsVerbatimArguments = true] - No quoting or escaping of arguments is done on Windows. Ignored on Unix. This is set to true automatically when shell is specified and is CMD. 78 | * @return {Promise<{status:number, stdout:string, stderr:string, childJavaProcess:ChildProcess}>} - Command result (status, stdout, stderr, childJavaProcess) 79 | */ 80 | async run(userArguments, runOptions = {}) { 81 | runOptions.detached = typeof runOptions.detached === "undefined" ? false : runOptions.detached; 82 | runOptions.waitForErrorMs = typeof runOptions.waitForErrorMs === "undefined" ? 500 : runOptions.waitForErrorMs; 83 | runOptions.cwd = typeof runOptions.cwd === "undefined" ? process.cwd() : runOptions.cwd; 84 | runOptions.stdoutEncoding = typeof runOptions.stdoutEncoding === "undefined" ? "utf8" : runOptions.stdoutEncoding; 85 | runOptions.windowsVerbatimArguments = typeof runOptions.windowsVerbatimArguments === "undefined" ? true : runOptions.windowsVerbatimArguments; 86 | runOptions.windowless = typeof runOptions.windowless === "undefined" ? false : os.platform() !== "win32" ? false : runOptions.windowless; 87 | this.commandJavaArgs = (runOptions.javaArgs || []).concat(this.additionalJavaArgs); 88 | 89 | let javaExe = runOptions.windowless ? this.javaExecutableWindowless : this.javaExecutable; 90 | if (javaExe.toLowerCase().includes(".exe") && javaExe.includes(" ") && !javaExe.includes(`'`)) { 91 | // Java executable has been overridden by caller : use it 92 | javaExe = `"${path.resolve(javaExe)}"`; 93 | } else if (javaExe === "java" || javaExe === "javaw") { 94 | // Check if matching java version is present, install and update PATH if it is not 95 | await this.manageJavaInstall(); 96 | } 97 | 98 | const javaExeToUse = this.javaExecutableFromNodeJavaCaller ?? javaExe; 99 | const classPathStr = this.buildClasspathStr(); 100 | const javaArgs = this.buildArguments(classPathStr, (userArguments || []).concat(this.commandJavaArgs)); 101 | let stdout = ""; 102 | let stderr = ""; 103 | let child; 104 | const prom = new Promise((resolve) => { 105 | // Spawn java command line 106 | debug(`Java command: ${javaExeToUse} ${javaArgs.join(" ")}`); 107 | const spawnOptions = { 108 | detached: runOptions.detached, 109 | cwd: javaExeToUse === "java" || javaExeToUse === "javaw" ? runOptions.cwd : undefined, 110 | env: Object.assign({}, process.env), 111 | stdio: this.output === "console" ? "inherit" : runOptions.detached ? "ignore" : "pipe", 112 | windowsHide: true, 113 | windowsVerbatimArguments: runOptions.windowsVerbatimArguments, 114 | }; 115 | if (javaExeToUse.includes(" ")) { 116 | spawnOptions.shell = true; 117 | } 118 | child = spawn(javaExeToUse, javaArgs, spawnOptions); 119 | 120 | // Gather stdout and stderr if they must be returned 121 | if (spawnOptions.stdio === "pipe") { 122 | child.stdout.setEncoding(`${runOptions.stdoutEncoding}`); 123 | child.stdout.on("data", (data) => { 124 | stdout += data; 125 | }); 126 | child.stderr.on("data", (data) => { 127 | stderr += data; 128 | }); 129 | } 130 | 131 | // Catch error 132 | child.on("error", (data) => { 133 | this.status = 666; 134 | stderr += "Java spawn error: " + data; 135 | resolve(); 136 | }); 137 | 138 | // Catch status code 139 | child.on("close", (code) => { 140 | this.status = code; 141 | resolve(); 142 | }); 143 | 144 | // Detach from main process in case detached === true 145 | if (runOptions.detached) { 146 | child.unref(); 147 | } 148 | }); 149 | 150 | if (runOptions.detached) { 151 | // Detached mode: Just wait a little amount of time in case you want to check a command error 152 | await new Promise((resolve) => 153 | setTimeout(() => { 154 | resolve(); 155 | }, runOptions.waitForErrorMs), 156 | ); 157 | } else { 158 | // Not detached mode: wait for Promise to be resolved 159 | await prom; 160 | } 161 | 162 | // Build result 163 | const result = { 164 | status: this.status, 165 | stdout: stdout, 166 | stderr: stderr, 167 | }; 168 | if (child) { 169 | result.childJavaProcess = child; 170 | } 171 | 172 | // Restore previous values of PATH & JAVA_HOME 173 | process.env["PATH"] = this.prevPath || process.env["PATH"]; 174 | process.env["JAVA_HOME"] = this.prevJavaHome || process.env["JAVA_HOME"]; 175 | 176 | return result; 177 | } 178 | 179 | // Translate the classpath from a string or string array into a string 180 | buildClasspathStr() { 181 | let classPathList = []; 182 | 183 | if (typeof this.classPath === "string") { 184 | classPathList = this.classPath.split(":"); 185 | } else { 186 | classPathList = this.classPath; 187 | } 188 | 189 | if (!this.useAbsoluteClassPaths) { 190 | classPathList = classPathList.map((classPathElt) => path.resolve(this.rootPath + path.sep + classPathElt)); 191 | } 192 | 193 | return classPathList.join(path.delimiter); 194 | } 195 | 196 | // Set first java arguments, then jar || classpath, then jar/class user arguments 197 | buildArguments(classPathStr, userArgs, windowsVerbatimArguments) { 198 | let javaArgs = []; 199 | let programArgs = []; 200 | for (const arg of userArgs) { 201 | if (arg.startsWith("-D") || arg.startsWith("-X") || this.commandJavaArgs.includes(arg)) { 202 | javaArgs.push(arg); 203 | } else { 204 | programArgs.push(arg); 205 | } 206 | } 207 | let allArgs = []; 208 | allArgs.push(...javaArgs); 209 | if (this.jar) { 210 | const jarPath = path.isAbsolute(this.jar) ? this.jar : path.join(this.rootPath, this.jar); 211 | 212 | allArgs.push( 213 | ...[ 214 | "-jar", 215 | os.platform() === "win32" && windowsVerbatimArguments ? `"${jarPath}"` : `${jarPath}`, 216 | ], 217 | ); 218 | } else { 219 | allArgs.push(...["-cp", os.platform() === "win32" && windowsVerbatimArguments ? `"${classPathStr}"` : classPathStr, this.mainClass]); 220 | } 221 | allArgs.push(...programArgs); 222 | return allArgs; 223 | } 224 | 225 | // Install Java if the found java version is not matching the requirements 226 | async manageJavaInstall() { 227 | if (this.javaExecutable !== 'java' && this.javaExecutable !== 'javaw') { 228 | // Do not search/install java if its path is sent as argument 229 | return; 230 | } 231 | if (await this.getInstallInCache()) { 232 | return; 233 | } 234 | let semverRule = '' 235 | if (this.minimumJavaVersion === this.maximumJavaVersion) { 236 | semverRule = `=${this.minimumJavaVersion}.x.x`; 237 | } else { 238 | semverRule = `>=${this.minimumJavaVersion}.0.0` + (this.maximumJavaVersion ? ` <=${this.maximumJavaVersion}.x.x` : ''); 239 | } 240 | const javaVersion = await this.getJavaVersion(); 241 | const requiresInstall = javaVersion === false ? true : !semver.satisfies(javaVersion, semverRule) 242 | if (requiresInstall) { 243 | // Check if the appropriate version has already been installed 244 | const { javaVersionHome = null, javaVersionBin = null } = await this.findJavaVersionHome(); 245 | if (javaVersionHome) { 246 | // Matching java version has been found: use it 247 | this.javaHome = javaVersionHome; 248 | this.javaBin = javaVersionBin; 249 | await this.addJavaInPath(); 250 | this.setJavaExecutableFromNodeJavaCaller(this.javaBin); 251 | return; 252 | } 253 | 254 | // Inform user that the installation is pending 255 | const requiredMsg = 256 | this.minimumJavaVersion !== this.maximumJavaVersion 257 | ? `Java ${this.javaType ? this.javaType : "jre or jdk"} between ${this.minimumJavaVersion} and ${this.maximumJavaVersion 258 | } is required ` 259 | : `Java ${this.javaType ? this.javaType : "jre or jdk"} ${this.minimumJavaVersion} is required`; 260 | console.log(requiredMsg); 261 | const javaVersionToInstall = this.maximumJavaVersion || this.minimumJavaVersion; 262 | const javaTypeToInstall = this.javaType || "jre"; 263 | console.log(`Installing Java ${javaTypeToInstall} ${javaVersionToInstall} in ${this.javaCallerSupportDir}...`); 264 | 265 | // Create a directory for installing Java and ensure it contains a dummy package.json 266 | await fse.ensureDir(this.javaCallerSupportDir, { mode: "0777" }); 267 | const packageJson = `${this.javaCallerSupportDir + path.sep}package.json`; 268 | if (!fse.existsSync(packageJson)) { 269 | const packageJsonContent = { 270 | name: "java-caller-support", 271 | version: "1.0.0", 272 | description: "Java installations by java-caller (https://github.com/nvuillam/node-java-caller)", 273 | }; 274 | await fse.writeFile(packageJson, JSON.stringify(packageJsonContent), "utf8"); 275 | } 276 | 277 | // Install appropriate java version using njre 278 | const njre = require("njre"); 279 | const njreOptions = { type: javaTypeToInstall, installPath: packageJson }; 280 | const installDir = await njre.install(javaVersionToInstall, njreOptions); 281 | console.log(`Installed Java ${javaTypeToInstall} ${javaVersionToInstall} in ${installDir}...`); 282 | 283 | // Call again this method: now matching java version will be found :) 284 | return await this.manageJavaInstall(); 285 | } 286 | } 287 | 288 | // Get matching version in java-caller cache 289 | async getInstallInCache() { 290 | if (globalThis.JAVA_CALLER_VERSIONS_CACHE != null) { 291 | for (const { version, file, java_home, java_bin } of globalThis.JAVA_CALLER_VERSIONS_CACHE) { 292 | if (this.checkMatchingJavaVersion(version, file)) { 293 | this.javaHome = java_home; 294 | this.javaBin = java_bin; 295 | await this.addJavaInPath(); 296 | this.setJavaExecutableFromNodeJavaCaller(this.javaBin); 297 | return true; 298 | } 299 | } 300 | } 301 | return false; 302 | } 303 | 304 | // Returns system default java version 305 | async getJavaVersion() { 306 | try { 307 | const { stderr } = await execPromise("java -version"); 308 | const match = /version "(.*?)"/.exec(stderr); 309 | 310 | // see https://openjdk.org/jeps/223 311 | // semver.coerce does awfully good job of parsing anything Java throws our way 312 | const version = semver.valid(semver.coerce(match[1])) 313 | if (version === null) { 314 | throw new Error(`unparsable java version: ${match[1]}`) 315 | } 316 | 317 | debug(`Found default java version ${version}`); 318 | return version; 319 | } catch (e) { 320 | debug(`Java not found: ${e.message}`); 321 | return false; 322 | } 323 | } 324 | 325 | // Browse locally installed java versions 326 | // check if one matches with javaType , minimumJavaVersion and maximumJavaVersion 327 | async findJavaVersionHome() { 328 | const javaInstallsTopDir = path.join(this.javaCallerSupportDir, "jre"); 329 | if (!fse.existsSync(javaInstallsTopDir)) { 330 | return {}; 331 | } 332 | 333 | return await fse.readdir(javaInstallsTopDir) 334 | .then((items) => 335 | items 336 | .filter((item) => fse.statSync(path.join(javaInstallsTopDir, item)).isDirectory()) 337 | .map((folder) => { 338 | const version = semver.coerce(folder) 339 | return { version, folder } 340 | }) 341 | .filter(({ version, folder }) => this.checkMatchingJavaVersion(version.major, folder)) 342 | .map(({ version, folder }) => { 343 | const home = path.join(javaInstallsTopDir, folder); 344 | const bin = path.join(home, this.getPlatformBinPath()); 345 | return { version, folder, home, bin } 346 | }) 347 | .find(({ bin }) => fse.existsSync(bin)) 348 | ) 349 | .then((match) => { 350 | if (!match) return {}; 351 | const { version, folder, home, bin } = match 352 | 353 | debug( 354 | `Found matching java bin: ${bin} for ${this.javaType ? this.javaType : "jre or jdk"} ${this.minimumJavaVersion}${this.maximumJavaVersion && this.maximumJavaVersion !== this.minimumJavaVersion ? " -> " + this.maximumJavaVersion : "+" 355 | }` 356 | ); 357 | this.addInCache(version.major, folder, home, bin); 358 | 359 | return { javaVersionHome: home, javaVersionBin: bin }; 360 | }) 361 | .catch((e) => { 362 | debug(`findJavaVersionHome failed: ${e}`) 363 | return {} 364 | }) 365 | } 366 | 367 | checkMatchingJavaVersion(versionFound, file) { 368 | if (versionFound < this.minimumJavaVersion) { 369 | return false; 370 | } 371 | if (this.maximumJavaVersion != null && versionFound > this.maximumJavaVersion) { 372 | return false; 373 | } 374 | if (this.javaType === "jre" && !file.includes("jre")) { 375 | return false; 376 | } else if (this.javaType === "jdk" && file.includes("jre")) { 377 | return false; 378 | } 379 | return true; 380 | } 381 | 382 | // Add java bin dir in PATH or JAVA_HOME 383 | async addJavaInPath() { 384 | this.prevPath = process.env["PATH"]; 385 | this.prevJavaHome = process.env["JAVA_HOME"]; 386 | // Add java-caller installed java version in PATH 387 | if (this.javaBin) { 388 | process.env["PATH"] = process.env["PATH"].includes(this.javaBin) 389 | ? process.env["PATH"] 390 | : this.javaBin + path.delimiter + process.env["PATH"]; 391 | process.env["JAVA_HOME"] = this.javaHome; 392 | } 393 | // If JAVA_HOME is set, but not jdk or jre, add it in PATH 394 | else if (process.env["JAVA_HOME"] && !process.env["PATH"].includes("jdk") && !process.env["PATH"].includes("jre")) { 395 | process.env["PATH"] = process.env["PATH"].includes(process.env["JAVA_HOME"]) 396 | ? process.env["PATH"] 397 | : process.env["JAVA_HOME"] + path.sep + this.getPlatformBinPath() + path.delimiter + process.env["PATH"]; 398 | } 399 | if (process.env["PATH"] !== this.prevPath) { 400 | debug("Updated PATH with value: " + process.env["PATH"]); 401 | } 402 | } 403 | 404 | getPlatformBinPath() { 405 | const platform = os.platform(); 406 | let binPath; 407 | switch (platform) { 408 | case "darwin": 409 | binPath = `Contents${path.sep}Home${path.sep}bin`; 410 | break; 411 | case "win32": 412 | binPath = "bin"; 413 | break; 414 | case "linux": 415 | binPath = "bin"; 416 | break; 417 | default: 418 | this.fail(`unsupported platform: ${platform}`); 419 | } 420 | return binPath; 421 | } 422 | 423 | setJavaExecutableFromNodeJavaCaller(javaBinPath) { 424 | this.javaExecutableFromNodeJavaCaller = path.join( 425 | javaBinPath, 426 | os.platform() === "win32" ? "java.exe" : "java"); 427 | if (this.javaExecutableFromNodeJavaCaller.includes(" ") && !this.javaExecutableFromNodeJavaCaller.startsWith('"')) { 428 | this.javaExecutableFromNodeJavaCaller = `"${path.resolve(this.javaExecutableFromNodeJavaCaller)}"` 429 | } 430 | } 431 | 432 | fail(reason) { 433 | console.error(reason); 434 | this.status = 666; 435 | } 436 | 437 | addInCache(version, file, java_home, java_bin) { 438 | if (globalThis.JAVA_CALLER_VERSIONS_CACHE == null) { 439 | globalThis.JAVA_CALLER_VERSIONS_CACHE = []; 440 | } 441 | globalThis.JAVA_CALLER_VERSIONS_CACHE.push({ version, file, java_home, java_bin }); 442 | } 443 | } 444 | 445 | module.exports = { JavaCaller }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "java-caller", 3 | "version": "4.2.1", 4 | "description": "Library to easily call java from node sources. Automatically installs java if not present", 5 | "main": "./lib/index.js", 6 | "files": [ 7 | "lib/" 8 | ], 9 | "scripts": { 10 | "lint:fix": "eslint **/*.js --fix && prettier --write \"./lib/**/*.{js,jsx,json}\" --tab-width 4 --print-width 150", 11 | "java:compile": "javac -d test/java/dist -source 8 -target 1.8 test/java/src/com/nvuillam/javacaller/JavaCallerTester.java", 12 | "java:jar": "cd test/java/dist && jar -cvfm ./../jar/JavaCallerTester.jar ./../jar/manifest/Manifest.txt com/nvuillam/javacaller/*.class && jar -cvfm ./../jar/JavaCallerTesterRunnable.jar ./../jar/manifest-runnable/Manifest.txt com/nvuillam/javacaller/*.class", 13 | "test": "mocha \"test/**/*.test.js\"", 14 | "test:coverage": "nyc npm run test", 15 | "test:debug": "env DEBUG=java-caller mocha --reporter spec \"test/**/*.test.js\"" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "git+https://github.com/nvuillam/node-java-caller.git" 20 | }, 21 | "keywords": [ 22 | "java", 23 | "caller", 24 | "classpath", 25 | "jar", 26 | "node", 27 | "npm", 28 | "javascript", 29 | "class" 30 | ], 31 | "author": "Nicolas Vuillamy", 32 | "license": "MIT", 33 | "bugs": { 34 | "url": "https://github.com/nvuillam/node-java-caller/issues" 35 | }, 36 | "homepage": "https://github.com/nvuillam/node-java-caller#readme", 37 | "dependencies": { 38 | "debug": "^4.3.4", 39 | "fs-extra": "^11.1.1", 40 | "njre": "^1.4.2", 41 | "semver": "^7.5.4" 42 | }, 43 | "devDependencies": { 44 | "@babel/eslint-parser": "^7.22.15", 45 | "eslint": "^9.0.0", 46 | "mocha": "^11.0.0", 47 | "nyc": "^17.0.0", 48 | "prettier": "^3.1.0", 49 | "which": "^4.0.0" 50 | }, 51 | "engines": { 52 | "node": ">=12.0.0" 53 | }, 54 | "mocha": { 55 | "require": [ 56 | "test/helpers/init.js" 57 | ], 58 | "watch-extensions": [ 59 | "js" 60 | ], 61 | "recursive": true, 62 | "reporter": "spec", 63 | "timeout": "300000" 64 | }, 65 | "nyc": { 66 | "include": [ 67 | "lib/**" 68 | ], 69 | "extension": [ 70 | ".js" 71 | ], 72 | "reporter": [ 73 | "html" 74 | ], 75 | "all": true 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": ["config:base"], 4 | "packageRules": [ 5 | { 6 | "matchPackagePatterns": [".*"], 7 | "matchUpdateTypes": ["minor", "patch"], 8 | "groupName": "all non-major dependencies", 9 | "groupSlug": "all-minor-patch" 10 | } 11 | ] 12 | } -------------------------------------------------------------------------------- /test/helpers/common.js: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env node 2 | const assert = require("assert"); 3 | 4 | // Reset codeNarcCallsCounter before each test 5 | const beforeEachTestCase = function () { 6 | // Reinitialize java-caller cache 7 | globalThis.NODE_JAVA_CALLER_IS_INITIALIZED = false; 8 | }; 9 | 10 | function checkStatus(statusCode, status, stdout, stderr) { 11 | assert(status === statusCode, `Status is ${statusCode} (${status} returned)\nstdout:\n${stdout}\nstderr:\n${stderr}`); 12 | } 13 | 14 | function checkStdOutIncludes(textToCheck, stdout, stderr) { 15 | assert(stdout && stdout.includes(textToCheck), `stdout contains ${textToCheck}\nstdout:\n${stdout}\nstderr:\n${stderr}`); 16 | } 17 | 18 | function checkStdOutIncludesOneOf(textsToCheck, stdout, stderr) { 19 | assert(stdout && textsToCheck.filter(txt => stdout.includes(txt)).length > 0, 20 | `stdout contains one of ${JSON.stringify(textsToCheck)}\nstdout:\n${stdout}\nstderr:\n${stderr}`); 21 | } 22 | 23 | function checkStdErrIncludes(textToCheck, stdout, stderr) { 24 | assert(stderr && stderr.includes(textToCheck), `stderr contains ${textToCheck}\nstdout:\n${stdout}\nstderr:\n${stderr}`); 25 | } 26 | 27 | module.exports = { 28 | beforeEachTestCase, 29 | checkStatus, 30 | checkStdOutIncludes, 31 | checkStdOutIncludesOneOf, 32 | checkStdErrIncludes 33 | } 34 | 35 | -------------------------------------------------------------------------------- /test/helpers/init.js: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env node 2 | "use strict"; 3 | 4 | console.log("npm run test initialized"); 5 | // Activate debug log if we are in debug mode 6 | const debug = typeof v8debug === "object" || /--debug|--inspect|--inspect-brk/.test(process.execArgv.join(" ")); 7 | if (debug) { 8 | require("debug").enable("java-caller"); 9 | } 10 | 11 | // Reinitialize cache 12 | globalThis.JAVA_CALLER_VERSIONS_CACHE = null; 13 | -------------------------------------------------------------------------------- /test/java-caller.test.js: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env node 2 | "use strict"; 3 | const { JavaCaller } = require('../lib/index'); 4 | const os = require("os"); 5 | const which = require("which"); 6 | const path = require('path'); 7 | 8 | const { 9 | beforeEachTestCase, 10 | checkStatus, 11 | checkStdOutIncludes, 12 | checkStdErrIncludes 13 | } = require("./helpers/common"); 14 | const { JavaCallerCli } = require('../lib/cli'); 15 | 16 | describe("Call with classes", () => { 17 | beforeEach(beforeEachTestCase); 18 | 19 | it("should call JavaCallerTester.class attached", async () => { 20 | const java = new JavaCaller({ 21 | classPath: 'test/java/dist', 22 | mainClass: 'com.nvuillam.javacaller.JavaCallerTester' 23 | }); 24 | const { status, stdout, stderr } = await java.run(); 25 | 26 | checkStatus(0, status, stdout, stderr); 27 | checkStdOutIncludes(`JavaCallerTester is called !`, stdout, stderr); 28 | }); 29 | 30 | it("should call JavaCallerTester.class detached", async () => { 31 | const java = new JavaCaller({ 32 | classPath: 'test/java/dist', 33 | mainClass: 'com.nvuillam.javacaller.JavaCallerTester' 34 | }); 35 | const { status, stdout, stderr, childJavaProcess } = await java.run(['--sleep'], { detached: true }); 36 | childJavaProcess.kill('SIGINT'); 37 | checkStatus(0, status, stdout, stderr); 38 | }); 39 | 40 | it("should call JavaCallerTester.class using javaw", async () => { 41 | const java = new JavaCaller({ 42 | classPath: 'test/java/dist', 43 | mainClass: 'com.nvuillam.javacaller.JavaCallerTester' 44 | }); 45 | const { status, stdout, stderr } = await java.run(['--sleep'], { windowless: true }); 46 | checkStatus(0, status, stdout, stderr); 47 | }); 48 | 49 | 50 | it("should call JavaCallerTester.class with proper stdout encoding", async () => { 51 | const java = new JavaCaller({ 52 | classPath: 'test/java/dist', 53 | mainClass: 'com.nvuillam.javacaller.JavaCallerTester' 54 | }); 55 | const { status, stdout, stderr, childJavaProcess } = await java.run(['--sleep'], { stdoutEncoding: 'binary' }); 56 | childJavaProcess.kill('SIGINT'); 57 | checkStatus(0, status, stdout, stderr); 58 | }); 59 | 60 | it("should call JavaCallerTester.class with a classPath array", async () => { 61 | const java = new JavaCaller({ 62 | classPath: ['test/java/dist'], 63 | mainClass: 'com.nvuillam.javacaller.JavaCallerTester' 64 | }); 65 | const { status, stdout, stderr } = await java.run(); 66 | 67 | checkStatus(0, status, stdout, stderr); 68 | checkStdOutIncludes(`JavaCallerTester is called !`, stdout, stderr); 69 | }); 70 | 71 | it("should call JavaCallerTester.class with absolute classpaths", async () => { 72 | const java = new JavaCaller({ 73 | classPath: __dirname + '/java/dist', 74 | useAbsoluteClassPaths: true, 75 | mainClass: 'com.nvuillam.javacaller.JavaCallerTester' 76 | }); 77 | const { status, stdout, stderr } = await java.run(); 78 | 79 | checkStatus(0, status, stdout, stderr); 80 | checkStdOutIncludes(`JavaCallerTester is called !`, stdout, stderr); 81 | }); 82 | 83 | it("should use call JavaCallerTester.class with java and custom arguments", async () => { 84 | const java = new JavaCaller({ 85 | classPath: 'test/java/dist', 86 | mainClass: 'com.nvuillam.javacaller.JavaCallerTester' 87 | }); 88 | const { status, stdout, stderr } = await java.run(['-Xms256m', '-Xmx1024m', '-customarg nico']); 89 | 90 | checkStatus(0, status, stdout, stderr); 91 | checkStdOutIncludes(`JavaCallerTester is called !`, stdout, stderr); 92 | checkStdOutIncludes(`-customarg`, stdout, stderr); 93 | checkStdOutIncludes(`nico`, stdout, stderr); 94 | }); 95 | 96 | it("should use call JavaCallerTester.class with javaArgs and custom arguments", async () => { 97 | const java = new JavaCaller({ 98 | classPath: 'test/java/dist', 99 | mainClass: 'com.nvuillam.javacaller.JavaCallerTester' 100 | }); 101 | const { status, stdout, stderr } = await java.run(['-customarg','nico'],{javaArgs: ['-Xms256m', '-Xmx1024m']}); 102 | 103 | checkStatus(0, status, stdout, stderr); 104 | checkStdOutIncludes(`JavaCallerTester is called !`, stdout, stderr); 105 | checkStdOutIncludes(`-customarg`, stdout, stderr); 106 | checkStdOutIncludes(`nico`, stdout, stderr); 107 | }); 108 | 109 | it("should call JavaCallerTester.class in JavaCallerTester.jar", async () => { 110 | const java = new JavaCaller({ 111 | classPath: 'test/java/jar/JavaCallerTester.jar', 112 | mainClass: 'com.nvuillam.javacaller.JavaCallerTester' 113 | }); 114 | const { status, stdout, stderr } = await java.run(); 115 | 116 | checkStatus(0, status, stdout, stderr); 117 | checkStdOutIncludes(`JavaCallerTester is called !`, stdout, stderr); 118 | }); 119 | 120 | it("should call JavaCallerTester.class in JavaCallerTester.jar (override java)", async () => { 121 | let javaPath; 122 | try { 123 | javaPath = which.sync("java"); 124 | } catch (e) { 125 | console.log("Java not found: ignore test method"); 126 | } 127 | if (javaPath) { 128 | console.log(`Java found: ${javaPath}`); 129 | const java = new JavaCaller({ 130 | classPath: 'test/java/jar/JavaCallerTester.jar', 131 | mainClass: 'com.nvuillam.javacaller.JavaCallerTester', 132 | javaExecutable: javaPath, 133 | javaOptions: "-Xms512m,-Xmx2g" 134 | }); 135 | const { status, stdout, stderr } = await java.run(); 136 | 137 | checkStatus(0, status, stdout, stderr); 138 | checkStdOutIncludes(`JavaCallerTester is called !`, stdout, stderr); 139 | } 140 | }); 141 | 142 | it("should call JavaCallerTester.class in JavaCallerTesterRunnable.jar", async () => { 143 | const java = new JavaCaller({ 144 | jar: 'test/java/jar/JavaCallerTesterRunnable.jar', 145 | }); 146 | const { status, stdout, stderr } = await java.run(); 147 | 148 | checkStatus(0, status, stdout, stderr); 149 | checkStdOutIncludes(`JavaCallerTester is called !`, stdout, stderr); 150 | }); 151 | 152 | it("should trigger a class not found error", async () => { 153 | const java = new JavaCaller({ 154 | classPath: 'nawak', 155 | mainClass: 'nimpor.te.quoi' 156 | }); 157 | const { status, stdout, stderr } = await java.run(); 158 | 159 | checkStatus(1, status, stdout, stderr); 160 | checkStdErrIncludes(`nimpor.te.quoi`, stdout, stderr); 161 | }); 162 | 163 | it("should trigger a node spawn error", async () => { 164 | const java = new JavaCaller({ 165 | classPath: 'nawak', 166 | mainClass: 'nimpor.te.quoi', 167 | javaExecutable: '/not/ there/java/bin/java.exe' 168 | }); 169 | const { status, stdout, stderr } = await java.run(); 170 | 171 | checkStatus(os.platform() === "win32" ? 1 : 127, status, stdout, stderr); 172 | }); 173 | 174 | it("should use JavaCallerCli", async () => { 175 | const javaCli = new JavaCallerCli("examples/cli_app/lib"); 176 | await javaCli.process(); 177 | }); 178 | 179 | it("Should work with an absolute path", async () => { 180 | const absolutePath = path.join(process.cwd(), "test/java/jar/JavaCallerTesterRunnable.jar"); 181 | 182 | const java = new JavaCaller({ 183 | jar: absolutePath, 184 | }); 185 | const { status, stdout, stderr } = await java.run(); 186 | 187 | checkStatus(0, status, stdout, stderr); 188 | checkStdOutIncludes(`JavaCallerTester is called !`, stdout, stderr); 189 | }); 190 | }); 191 | -------------------------------------------------------------------------------- /test/java-install.test.js: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env node 2 | "use strict"; 3 | const os = require("os"); 4 | const { JavaCaller } = require('../lib/index'); 5 | 6 | const { 7 | beforeEachTestCase, 8 | checkStatus, 9 | checkStdOutIncludes, 10 | checkStdOutIncludesOneOf, 11 | } = require("./helpers/common"); 12 | 13 | const javaVersionsToTest = os.platform() === "darwin" 14 | ? [11, 17, 20, 21] 15 | : [8, 11, 14, 17, 20, 21]; 16 | const javaTypesToTest = ['jre', 'jdk']; 17 | 18 | describe("Test all installs", () => { 19 | beforeEach(beforeEachTestCase); 20 | 21 | it(`should use Java jre from 17 to 21`, async () => { 22 | const java = new JavaCaller({ 23 | classPath: 'test/java/dist', 24 | mainClass: 'com.nvuillam.javacaller.JavaCallerTester', 25 | minimumJavaVersion: 17, 26 | maximumJavaVersion: 21, 27 | javaType: "jre" 28 | }); 29 | const { status, stdout, stderr } = await java.run(); 30 | 31 | checkStatus(0, status, stdout, stderr); 32 | checkStdOutIncludes(`JavaCallerTester is called !`, stdout, stderr); 33 | checkStdOutIncludesOneOf([ 34 | `17`, 35 | `21` 36 | ], stdout, stderr) 37 | }); 38 | 39 | for (const javaVersion of javaVersionsToTest) { 40 | for (const javaType of javaTypesToTest) { 41 | 42 | it(`should install and use Java ${javaType} ${javaVersion}`, async () => { 43 | const java = new JavaCaller({ 44 | classPath: 'test/java/dist', 45 | mainClass: 'com.nvuillam.javacaller.JavaCallerTester', 46 | minimumJavaVersion: javaVersion, 47 | maximumJavaVersion: javaVersion, 48 | javaType: javaType 49 | }); 50 | const { status, stdout, stderr } = await java.run(); 51 | 52 | checkStatus(0, status, stdout, stderr); 53 | checkStdOutIncludes(`JavaCallerTester is called !`, stdout, stderr); 54 | checkStdOutIncludes(`Java runtime version ${javaVersion}`, stdout, stderr) 55 | }); 56 | } 57 | } 58 | 59 | }); 60 | 61 | 62 | -------------------------------------------------------------------------------- /test/java/dist/com/nvuillam/javacaller/JavaCallerTester.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nvuillam/node-java-caller/dd41cf16a7df82e386f0b66dc312cb3e6105d2c3/test/java/dist/com/nvuillam/javacaller/JavaCallerTester.class -------------------------------------------------------------------------------- /test/java/jar/JavaCallerTester.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nvuillam/node-java-caller/dd41cf16a7df82e386f0b66dc312cb3e6105d2c3/test/java/jar/JavaCallerTester.jar -------------------------------------------------------------------------------- /test/java/jar/JavaCallerTesterRunnable.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nvuillam/node-java-caller/dd41cf16a7df82e386f0b66dc312cb3e6105d2c3/test/java/jar/JavaCallerTesterRunnable.jar -------------------------------------------------------------------------------- /test/java/jar/JavaCallerTesterRunnable.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nvuillam/node-java-caller/dd41cf16a7df82e386f0b66dc312cb3e6105d2c3/test/java/jar/JavaCallerTesterRunnable.zip -------------------------------------------------------------------------------- /test/java/jar/manifest-runnable/Manifest.txt: -------------------------------------------------------------------------------- 1 | Manifest-version: 1.0 2 | Created-By: Nicolas Vuillamy 3 | Main-Class: com.nvuillam.javacaller.JavaCallerTester 4 | -------------------------------------------------------------------------------- /test/java/jar/manifest/Manifest.txt: -------------------------------------------------------------------------------- 1 | Manifest-version: 1.0 2 | Created-By: Nicolas Vuillamy -------------------------------------------------------------------------------- /test/java/src/com/nvuillam/javacaller/JavaCallerTester.java: -------------------------------------------------------------------------------- 1 | package com.nvuillam.javacaller; 2 | 3 | import java.lang.InterruptedException; 4 | import java.util.concurrent.TimeUnit; 5 | 6 | public class JavaCallerTester 7 | { 8 | public static void main(String[] args) 9 | { 10 | System.out.println("JavaCallerTester is called !"); 11 | System.out.println(java.util.Arrays.toString(args)); 12 | if (args.length > 0 && args[0] != null && args[0] == "--sleep") { 13 | try { 14 | TimeUnit.MINUTES.sleep(1); 15 | } catch (InterruptedException eInterrupt) { 16 | System.err.println("JavaCallerTester interrupted !"); 17 | } catch (Throwable t) { 18 | System.err.println("JavaCallerTester crashed !"); 19 | } 20 | } 21 | System.out.println("Java runtime version "+getVersion()); 22 | } 23 | 24 | private static int getVersion() { 25 | String version = System.getProperty("java.version"); 26 | if (version.startsWith("1.")) { 27 | version = version.substring(2, 3); 28 | } 29 | else { 30 | int dot = version.indexOf("."); 31 | if (dot != -1) { 32 | version = version.substring(0, dot); 33 | } 34 | } 35 | return Integer.parseInt(version); 36 | } 37 | } --------------------------------------------------------------------------------