pax_global_header00006660000000000000000000000064140567151670014526gustar00rootroot0000000000000052 comment=de155ed80ef38c3b9ac7e86f9ceb125406dda06c jpype-1.3.0/000077500000000000000000000000001405671516700126565ustar00rootroot00000000000000jpype-1.3.0/.azure/000077500000000000000000000000001405671516700140625ustar00rootroot00000000000000jpype-1.3.0/.azure/build.yml000066400000000000000000000042361405671516700157110ustar00rootroot00000000000000# JPype CI pipeline pr: branches: include: - master - releases/* paths: include: - .azure/build.yml - doc/* - setup.py - setupext/* - jpype/* - native/* - test/* variables: # indicate whether the testsuite should skip long running tests or not. - name: jpypetest.fast value: 'false' jobs: - job: Deps pool: vmImage: "ubuntu-16.04" steps: - template: scripts/ivy.yml - job: Documentation pool: vmImage: "ubuntu-16.04" steps: - template: scripts/documentation.yml - job: Coverage pool: vmImage: "ubuntu-16.04" dependsOn: Deps steps: - template: scripts/deps.yml - template: scripts/coverage.yml - job: Tracing pool: vmImage: "ubuntu-16.04" steps: - template: scripts/tracing.yml - job: Test dependsOn: Deps strategy: matrix: linux-3.5: imageName: "ubuntu-16.04" python.version: '3.5' linux-3.6: imageName: "ubuntu-16.04" python.version: '3.6' linux-3.7: imageName: "ubuntu-16.04" python.version: '3.7' linux-3.8: imageName: "ubuntu-16.04" python.version: '3.8' linux-3.9: imageName: "ubuntu-16.04" python.version: '3.9' windows-3.5: imageName: "vs2017-win2016" python.version: '3.5' windows-3.6: imageName: "vs2017-win2016" python.version: '3.6' windows-3.7: imageName: "vs2017-win2016" python.version: '3.7' windows-3.8: imageName: "vs2017-win2016" python.version: '3.8' #windows-3.9: #imageName: "vs2017-win2016" #python.version: '3.9' #jpypetest.fast: 'true' mac-3.9: imageName: "macos-10.14" python.version: '3.9' jpypetest.fast: 'true' pool: vmImage: $(imageName) steps: - template: scripts/deps.yml - template: scripts/test.yml - job: Debug condition: eq(1,0) dependsOn: Deps strategy: matrix: linux-3.8: imageName: "ubuntu-16.04" jdk_version: "1.11" python.version: '3.8' pool: vmImage: $(imageName) steps: - template: scripts/deps.yml - template: scripts/debug.yml jpype-1.3.0/.azure/doc-requirements.txt000066400000000000000000000002301405671516700201040ustar00rootroot00000000000000 # TODO: consider unpinning these? Pygments==2.7.4 docutils==0.14 commonmark==0.8.1 recommonmark==0.5.0 sphinx sphinx-rtd-theme readthedocs-sphinx-ext jpype-1.3.0/.azure/release.yml000066400000000000000000000056071405671516700162350ustar00rootroot00000000000000# JPype Release pipeline trigger: none pr: branches: include: - releases/* paths: include: - .bumpversion.cfg - .azure/release.yml variables: package_name: JPype1 stages: - stage: Initial jobs: - job: SourceDistribution pool: vmImage: "ubuntu-latest" steps: - template: scripts/sdist.yml - template: scripts/ivy.yml - stage: Package jobs: # From https://iscinumpy.gitlab.io/post/azure-devops-python-wheels/ - job: ManyLinux condition: eq(1,1) strategy: matrix: # Disabled because it is fetching beta images # 64Bit2010: # arch: x86_64 # plat: manylinux2010_x86_64 # image: quay.io/pypa/manylinux2010_x86_64 # python.architecture: x64 # 64Bit2014: # arch: aarch64 # plat: manylinux2014_aarch64 # image: quay.io/pypa/manylinux2014_aarch64 # python.architecture: aarch64 64Bit: arch: x86_64 plat: manylinux1_x86_64 image: quay.io/pypa/manylinux1_x86_64 python.architecture: x64 32Bit: arch: i686 plat: manylinux1_i686 image: quay.io/pypa/manylinux1_i686 python.architecture: x86 pool: vmImage: "ubuntu-latest" steps: - template: scripts/deps.yml - template: scripts/wheels-linux.yml - template: scripts/publish-dist.yml - job: Windows_x64 condition: eq(1,1) strategy: matrix: Python36: python.version: '3.6' python.architecture: 'x64' Python37: python.version: '3.7' python.architecture: 'x64' Python38: python.version: '3.8' python.architecture: 'x64' Python39: python.version: '3.9' python.architecture: 'x64' pool: vmImage: 'vs2017-win2016' steps: - template: scripts/deps.yml - task: UsePythonVersion@0 inputs: versionSpec: '$(python.version)' architecture: '$(python.architecture)' - template: scripts/jdk.yml parameters: version: '8' - template: scripts/wheels.yml - template: scripts/publish-dist.yml - job: OSX condition: eq(1,1) variables: python.architecture: 'x64' strategy: matrix: Python36: python.version: '3.6' Python37: python.version: '3.7' Python38: python.version: '3.8' Python39: python.version: '3.9' pool: vmImage: "macOS-10.14" steps: - template: scripts/deps.yml - script: .azure/scripts/osx-python.sh '$(python.version)' displayName: Install Python.org Python - template: scripts/jdk.yml parameters: version: '8' - template: scripts/wheels.yml - template: scripts/publish-dist.yml jpype-1.3.0/.azure/scripts/000077500000000000000000000000001405671516700155515ustar00rootroot00000000000000jpype-1.3.0/.azure/scripts/build-wheels.sh000077500000000000000000000017151405671516700205000ustar00rootroot00000000000000#!/bin/bash set -e -x # Collect the pythons pys=(/opt/python/*/bin) # Filter out Python 3.4 pys=(${pys[@]//*34*/}) pys=(${pys[@]//*27*/}) # Compile wheels for PYBIN in "${pys[@]}"; do echo "Compile $PYBIN" ls -l /io/dist "${PYBIN}/pip" install -r /io/dev-requirements.txt "${PYBIN}/pip" wheel /io/dist/$package_name-*.tar.gz -w wheelhouse/ -v done echo "==============" # Bundle external shared libraries into the wheels for whl in wheelhouse/$package_name-*.whl; do echo "Audit $whl" auditwheel repair --plat $PLAT "$whl" -w /io/wheelhouse/ done echo "==============" # Install packages and test for PYBIN in "${pys[@]}"; do echo "Test install $PYBIN $package_name" "${PYBIN}/python" -m pip install $package_name --no-index -f /io/wheelhouse # Manylinux does not have a JVM so there is no way to test the wheel in the docker # "${PYBIN}/pip" install -r /io/test-requirements.txt # "${PYBIN}/pytest" /io/test/jpypetest done jpype-1.3.0/.azure/scripts/coverage.yml000066400000000000000000000026771405671516700201030ustar00rootroot00000000000000# This task produces the coverage reports and publishes them to codecov. steps: - task: UsePythonVersion@0 inputs: versionSpec: '3.8' - template: jdk.yml parameters: version: 11 - script: | python setup.py test_java pip install gcovr pytest-cov jedi pip install -r test-requirements.txt pip install numpy typing_extensions displayName: 'Install requirements' - script: | python setup.py --enable-coverage --enable-build-jar build_ext --inplace displayName: 'Build' - script: | python -m pytest -v -s test/jpypetest --cov=jpype --cov-report=xml:coverage_py.xml --classpath="build/classes" --jacoco --checkjni displayName: 'Test' - script: | gcovr -r . --xml -o coverage.xml --exclude-unreachable-branches --exclude-throw-branches java -jar lib/org.jacoco.cli-0.8.5-nodeps.jar report build/coverage/jacoco.exec --classfiles build/classes/ --xml coverage_java.xml --sourcefiles native/java bash <(curl -s https://codecov.io/bash) -f coverage.xml -f coverage_py.xml -f coverage_java.xml -X gcov displayName: 'Report' - task: PublishCodeCoverageResults@1 inputs: codeCoverageTool: 'JaCoCo' summaryFileLocation: coverage_java.xml pathToSources: native/java - task: PublishCodeCoverageResults@1 inputs: codeCoverageTool: 'cobertura' summaryFileLocation: coverage.xml - task: PublishCodeCoverageResults@1 inputs: codeCoverageTool: 'cobertura' summaryFileLocation: coverage_py.xml jpype-1.3.0/.azure/scripts/debug.yml000066400000000000000000000011751405671516700173660ustar00rootroot00000000000000# This task is used when there is an error in the CI that can't be # replicated locally. steps: - task: UsePythonVersion@0 inputs: versionSpec: '$(python.version)' - script: | sudo apt install gdb python setup.py sdist pip install dist/* displayName: 'Build module' - script: python -c "import jpype" displayName: 'Check module' - script: | python setup.py test_java pip install -r test-requirements.txt pip install numpy jedi gdb -ex 'handle SIGSEGV nostop noprint pass' -ex "run -m pytest -v test/jpypetest/test_jstring.py --checkjni" -ex "bt" -ex "quit" python displayName: 'Debug module' jpype-1.3.0/.azure/scripts/deps.yml000066400000000000000000000001631405671516700172270ustar00rootroot00000000000000steps: - task: DownloadPipelineArtifact@2 inputs: source: current artifact: artifact_Deps path: lib jpype-1.3.0/.azure/scripts/documentation.yml000066400000000000000000000012641405671516700211500ustar00rootroot00000000000000# This task tries to verify if the documentation will build properly on RTD steps: - task: UsePythonVersion@0 inputs: versionSpec: '3.8' - script: | pip install --exists-action=w --no-cache-dir -r test-requirements.txt -r .azure/doc-requirements.txt displayName: 'Install requirements' - script: | python -m sphinx -T -b readthedocs -d _build/doctrees-readthedocs -D language=en doc build/html displayName: 'Check documentation' - task: CopyFiles@2 inputs: contents: 'build/html/**' targetFolder: $(Build.ArtifactStagingDirectory) - task: PublishBuildArtifacts@1 inputs: pathToPublish: $(Build.ArtifactStagingDirectory) artifactName: documentation jpype-1.3.0/.azure/scripts/ivy.yml000066400000000000000000000005551405671516700171100ustar00rootroot00000000000000steps: - script: | wget "https://repo1.maven.org/maven2/org/apache/ivy/ivy/2.4.0/ivy-2.4.0.jar" -P lib java -jar lib/ivy-2.4.0.jar -ivy ivy.xml -retrieve 'lib/[artifact]-[revision](-[classifier]).[ext]' displayName: 'Resolve' - task: PublishPipelineArtifact@0 inputs: artifactName: 'artifact_Deps' targetPath: 'lib' displayName: Publish deps jpype-1.3.0/.azure/scripts/jdk.yml000066400000000000000000000006171405671516700170500ustar00rootroot00000000000000parameters: - name: version type: string default: 8 steps: - script: | set v="##vso[task.setvariable variable=JAVA_HOME]%JAVA_HOME_${{parameters.version}}_X64%" echo %v:"=% condition: eq(variables['Agent.OS'], 'Windows_NT') - script: | echo "##vso[task.setvariable variable=JAVA_HOME]$(JAVA_HOME_${{parameters.version}}_X64)" condition: ne(variables['Agent.OS'], 'Windows_NT') jpype-1.3.0/.azure/scripts/osx-python.sh000077500000000000000000000012121405671516700202340ustar00rootroot00000000000000#!/usr/bin/env bash PYTHON_VERSION="$1" case $PYTHON_VERSION in 3.6) FULL_VERSION=3.6.8 ;; 3.7) FULL_VERSION=3.7.9 ;; 3.8) FULL_VERSION=3.8.6 ;; 3.9) FULL_VERSION=3.9.0 ;; esac INSTALLER_NAME=python-$FULL_VERSION-macosx10.9.pkg URL=https://www.python.org/ftp/python/$FULL_VERSION/$INSTALLER_NAME PY_PREFIX=/Library/Frameworks/Python.framework/Versions set -e -x curl $URL > $INSTALLER_NAME sudo installer -pkg $INSTALLER_NAME -target / sudo rm /usr/local/bin/python sudo ln -s /usr/local/bin/python$PYTHON_VERSION /usr/local/bin/python which python python --version python -m ensurepip python -m pip install setuptools wheel jpype-1.3.0/.azure/scripts/publish-dist.yml000066400000000000000000000002331405671516700207010ustar00rootroot00000000000000steps: - task: PublishPipelineArtifact@0 inputs: artifactName: 'artifact_$(Agent.JobName)_$(Agent.OS)_$(python.architecture)' targetPath: 'dist' jpype-1.3.0/.azure/scripts/sdist.yml000066400000000000000000000004711405671516700174240ustar00rootroot00000000000000steps: - task: UsePythonVersion@0 inputs: versionSpec: '3.8' - script: | python -m pip install setuptools python setup.py sdist displayName: Build sdist - task: PublishPipelineArtifact@0 inputs: artifactName: 'artifact_SourceDistribution' targetPath: 'dist' displayName: Publish sdist jpype-1.3.0/.azure/scripts/test.yml000066400000000000000000000024441405671516700172570ustar00rootroot00000000000000# This task tests individual platforms and versions steps: - task: UsePythonVersion@0 inputs: versionSpec: '$(python.version)' - template: jdk.yml parameters: version: 11 - script: | python setup.py build_ext --inplace displayName: 'Build module' - script: | pip install numpy jedi typing_extensions python -c "import jpype" displayName: 'Check module' - script: | python setup.py test_java pip install -r test-requirements.txt displayName: 'Install test' - script: | python -m pytest -v --junit-xml=build/test/test.xml test/jpypetest --checkjni displayName: 'Test JDK 11' condition: eq(variables['jpypetest.fast'], 'false') - script: | python -m pytest -v --junit-xml=build/test/test.xml test/jpypetest --checkjni --fast displayName: 'Test JDK 11 (fast)' condition: eq(variables['jpypetest.fast'], 'true') # presence of jpype/ seems to confuse entry_points so `cd` elsewhere - script: | pip install . mkdir empty cd empty python -m PyInstaller.utils.run_tests --include_only jpype._pyinstaller. displayName: 'Test PyInstaller result' - task: PublishTestResults@2 condition: succeededOrFailed() inputs: testResultsFiles: 'build/test/test.xml' testRunTitle: 'Publish test results for Python $(python.version) with JDK 11' jpype-1.3.0/.azure/scripts/tracing.yml000066400000000000000000000003651405671516700177270ustar00rootroot00000000000000# This job verifies that nothing is broken in the tracing compile steps: - task: UsePythonVersion@0 inputs: versionSpec: '3.8' - script: | python setup.py --enable-tracing --enable-build-jar build_ext --inplace displayName: 'Build' jpype-1.3.0/.azure/scripts/wheels-linux.yml000066400000000000000000000014701405671516700207220ustar00rootroot00000000000000steps: - task: UsePythonVersion@0 inputs: versionSpec: '3.8' - task: DownloadPipelineArtifact@2 inputs: source: current artifact: artifact_SourceDistribution path: dist - script: | sudo apt-get update sudo apt-get install -y qemu qemu-user-static qemu-user binfmt-support sudo docker run --rm --privileged hypriot/qemu-register condition: and(succeeded(), eq(variables['arch'], 'aarch64')) displayName: 'Install QEMU' - script: | ls -l ls -l dist displayName: Sanity check - script: | set -ex docker run -e PLAT=$(plat) -e package_name=$(package_name) --rm -v `pwd`:/io $(image) /io/.azure/scripts/build-wheels.sh displayName: Build wheels - script: | ls -lh wheelhouse/ rm dist/* cp wheelhouse/$(package_name)*.whl dist/. displayName: Copy wheels jpype-1.3.0/.azure/scripts/wheels.yml000066400000000000000000000014711405671516700175660ustar00rootroot00000000000000# This job creates wheels for Windows/OSX steps: - script: | mkdir -p dist python -m pip install --upgrade pip python -m pip install --upgrade wheel setuptools displayName: 'Install dependencies' - script: | python -m pip wheel . -w wheelhouse/ displayName: 'Build wheel' - script: | ls -lh wheelhouse cp wheelhouse/$(package_name)* dist/. displayName: 'Show wheelhouse' - script: | python -m pip install JPype1 --no-index -f wheelhouse displayName: 'Install module' - script: | python setup.py test_java python -m pip install -r test-requirements.txt displayName: 'Install test' - script: | ls -l ls lib/ displayName: 'Check deps' - script: | python -m pytest -v --junit-xml=build/test/test.xml test/jpypetest --checkjni --fast displayName: 'Test module' jpype-1.3.0/.bumpversion.cfg000066400000000000000000000012211405671516700157620ustar00rootroot00000000000000[bumpversion] current_version = 1.3.0 commit = True tag = False parse = (?P\d+)\.(?P\d+)\.(?P\d+)(\_(?P[a-z]+)(?P\d+))? serialize = {major}.{minor}.{patch}_{release}{build} {major}.{minor}.{patch} [bumpversion:part:release] first_value = dev optional_value = prod values = dev prod [bumpversion:part:build] [bumpversion:file:setup.py] [bumpversion:file:native/python/pyjp_module.cpp] [bumpversion:file:jpype/__init__.py] [bumpversion:file:native/java/org/jpype/JPypeContext.java] [bumpversion:file:doc/CHANGELOG.rst] search = Latest Changes: replace = Latest Changes: - **{new_version} - {now:%Y-%m-%d}** jpype-1.3.0/.gitattributes000066400000000000000000000007661405671516700155620ustar00rootroot00000000000000* test=auto # Specify lf for all source files *.py text eol=lf *.cpp text eol=lf *.c text eol=lf *.h text eol=lf *.java text eol=lf *.rst text eol=lf *.sh text eol=lf *.cfg text eol=lf *.yml text eol=lf *.xsl text eol=lf *.css text eol=lf *.ps1 text eol=crlf *.cmd text eol=crlf *.bat text eol=crlf *.properties text eol=crlf README text eol=lf LICENSE text eol=lf Makefile text eol=lf Manifest.in text eol=lf *.xml text eol=lf *.md text *.txt text .gitignore text eol=lf .gitattributes text eol=lf jpype-1.3.0/.gitignore000077500000000000000000000025301405671516700146510ustar00rootroot00000000000000MANIFEST Makefile* *~ /test/classes/ /test/jars/ **/test.pic build/ .buildozer bin native/*.jar org.jpype.jar # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] # C extensions *.so *.dll # Distribution / packaging .Python env/ build/ develop-eggs/ dist/ downloads/ eggs/ lib/ lib64/ parts/ sdist/ var/ *.egg-info/ .installed.cfg *.egg # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .coverage jacoco.exec .cache nosetests.xml coverage*.xml # Translations *.mo *.pot # Django stuff: *.log # Sphinx documentation docs/_build/ # PyBuilder target/ /project/jpype_java/nbproject/private/ /project/jpype_cpython/nbproject/private/ /project/jpype_cpython/nbproject/Makefile* /project/jpype_java/nbproject/build-impl.xml /project/jpype_java/nbproject/genfiles.properties /project/jpype_java/dist /project/jpype_java/build /project/jpype_cpython/Makefile /project/jpype_cpython/nbproject/Package-Release.bash /project/jpype_python/nbproject/private/ /project/coverage/*.jar *.swp *.stackdump *.zip tmp doc/html native/jars docker/*.tar.gz docker/wheelhouse /.eggs /tmp* a.out .idea/ _build/ jacoco/ wheelhouse/ vc*.pdb *.class jpype-1.3.0/.readthedocs.yml000066400000000000000000000010011405671516700157340ustar00rootroot00000000000000# Read the Docs configuration file # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details # Required version: 2 # Build documentation in the docs/ directory with Sphinx sphinx: configuration: doc/conf.py # Optionally build your docs in additional formats such as PDF and ePub # formats: all # Optionally set the version of Python and requirements required to build your docs python: version: 3.8 install: - method: pip path: . extra_requirements: - docs jpype-1.3.0/AUTHORS.rst000066400000000000000000000005611405671516700145370ustar00rootroot00000000000000Authors ------- The original author: Steve Menard Current Maintainer: Luis Nell Huge thanks to these CONTRIBUTORS: * lazerscience * Koblaid * Michael Willis (michaelwillis) * awesomescot * Joe Quant (joequant) * Mario Rodas * David Moss * Stepan Kolesnik * Philip Smith * Bastian Bowe * Kristi * Martin K. Scherer * Dongwon Shin * rbprogrammer * Karl Einar Nelson jpype-1.3.0/LICENSE000066400000000000000000000227401405671516700136700ustar00rootroot00000000000000============== Apache License ============== :Version: 2.0 :Date: January 2004 :URL: http://www.apache.org/licenses/ ------------------------------------------------------------ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION ------------------------------------------------------------ 1. Definitions. --------------- **"License"** shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. **"Licensor"** shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. **"Legal Entity"** shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means *(i)* the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or *(ii)* ownership of fifty percent (50%) or more of the outstanding shares, or *(iii)* beneficial ownership of such entity. **"You"** (or **"Your"**) shall mean an individual or Legal Entity exercising permissions granted by this License. **"Source"** form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. **"Object"** form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. **"Work"** shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). **"Derivative Works"** shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. **"Contribution"** shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." **"Contributor"** shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. ------------------------------ Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. --------------------------- Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. ------------------ You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: - You must give any other recipients of the Work or Derivative Works a copy of this License; and - You must cause any modified files to carry prominent notices stating that You changed the files; and - You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and - If the Work includes a ``"NOTICE"`` text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such ``NOTICE`` file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a ``NOTICE`` text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the ``NOTICE`` file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the ``NOTICE`` text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. ------------------------------- Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. -------------- This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the ``NOTICE`` file. 7. Disclaimer of Warranty. -------------------------- Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an **"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND**, either express or implied, including, without limitation, any warranties or conditions of **TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE**. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. --------------------------- In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. ---------------------------------------------- While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. **END OF TERMS AND CONDITIONS** jpype-1.3.0/MANIFEST.in000066400000000000000000000003011405671516700144060ustar00rootroot00000000000000recursive-include native *.h *.xml *.java *.jar *.class recursive-include examples * include *.rst doc/* LICENSE # include everything under test/ graft test graft setupext global-exclude *.pyc jpype-1.3.0/NOTICE000066400000000000000000000036351405671516700135710ustar00rootroot00000000000000COPYRIGHT ========= Copyright (c) 2004-2008 Steve Menard Copyright (c) 2020 Lawrence Livermore National Security, LLC. Produced at the Lawrence Livermore National Laboratory LLNL-CODE- 812311 All rights reserved. LICENSE ======= Licensed under the Apache License, Version 2.0 (the "License"); you may not use this software except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. AUSPICES ======== This work was produced under the auspices of the U.S. Department of Energy by Lawrence Livermore National Laboratory under Contract DE-AC52-07NA27344. This work was prepared as an account of work sponsored by an agency of the United States Government. Neither the United States Government nor Lawrence Livermore National Security, LLC, nor any of their employees makes any warranty, expressed or implied, or assumes any legal liability or responsibility for the accuracy, completeness, or usefulness of any information, apparatus, product, or process disclosed, or represents that its use would not infringe privately owned rights. Reference herein to any specific commercial product, process, or service by trade name, trademark, manufacturer, or otherwise does not necessarily constitute or imply its endorsement, recommendation, or favoring by the United States Government or Lawrence Livermore National Security, LLC. The views and opinions of authors expressed herein do not necessarily state or reflect those of the United States Government or Lawrence Livermore National Security, LLC, and shall not be used for advertising or product endorsement purposes. jpype-1.3.0/README.rst000066400000000000000000000067411405671516700143550ustar00rootroot00000000000000.. image:: doc/logo.png :scale: 50 % :alt: JPype logo :align: center JPype ===== |implementation| |pyversions| |javaversions| |jvm| |platform| |license| JPype is a Python module to provide full access to Java from within Python. It allows Python to make use of Java only libraries, exploring and visualization of Java structures, development and testing of Java libraries, scientific computing, and much more. By gaining the best of both worlds using Python for rapid prototyping and Java for strong typed production code, JPype provides a powerful environment for engineering and code development. This is achieved not through re-implementing Python, as Jython has done, but rather through interfacing at the native level in both virtual machines. This shared memory based approach achieves decent computing performance, while providing the access to the entirety of CPython and Java libraries. :Code: `GitHub `_ :Issue tracker: `GitHub Issues `_ :Documentation: `Python Docs`_ :License: `Apache 2 License`_ :Build status: |TestsCI|_ |Docs|_ :Quality status: |Codecov|_ |lgtm_python|_ |lgtm_java|_ |lgtm_cpp|_ :Version: |PypiVersion|_ |Conda|_ The work on this project began on `Sourceforge `__. LLNL-CODE- 812311 .. |alerts| image:: https://img.shields.io/lgtm/alerts/g/jpype-project/jpype.svg?logo=lgtm&logoWidth=18 .. _alerts: https://lgtm.com/projects/g/jpype-project/jpype/alerts/ .. |lgtm_python| image:: https://img.shields.io/lgtm/grade/python/g/jpype-project/jpype.svg?logo=lgtm&logoWidth=18&label=python .. _lgtm_python: https://lgtm.com/projects/g/jpype-project/jpype/context:python .. |lgtm_java| image:: https://img.shields.io/lgtm/grade/java/g/jpype-project/jpype.svg?logo=lgtm&logoWidth=18&label=java .. _lgtm_java: https://lgtm.com/projects/g/jpype-project/jpype/context:java .. |lgtm_cpp| image:: https://img.shields.io/lgtm/grade/cpp/g/jpype-project/jpype.svg?logo=lgtm&logoWidth=18&label=C++ .. _lgtm_cpp: https://lgtm.com/projects/g/jpype-project/jpype/context:cpp .. |PypiVersion| image:: https://img.shields.io/pypi/v/Jpype1.svg .. _PypiVersion: https://badge.fury.io/py/JPype1 .. |Conda| image:: https://img.shields.io/conda/v/conda-forge/jpype1.svg .. _Conda: https://anaconda.org/conda-forge/jpype1 .. |TestsCI| image:: https://dev.azure.com/jpype-project/jpype/_apis/build/status/jpype-project.jpype?branchName=master .. _TestsCI: https://dev.azure.com/jpype-project/jpype/_build/latest?definitionId=1&branchName=master .. |Docs| image:: https://img.shields.io/readthedocs/jpype.svg .. _Docs: http://jpype.readthedocs.org/en/latest/ .. |Codecov| image:: https://codecov.io/gh/jpype-project/jpype/branch/master/graph/badge.svg .. _Codecov: https://codecov.io/gh/jpype-project/jpype .. |implementation| image:: https://img.shields.io/pypi/implementation/jpype1.svg .. |pyversions| image:: https://img.shields.io/pypi/pyversions/jpype1.svg .. |javaversions| image:: https://img.shields.io/badge/java-8%20%7C%209%20%7C%2011-purple.svg .. |jvm| image:: https://img.shields.io/badge/jvm-Open%20%7C%20Oracle%20%7C%20Corretto-purple.svg .. |platform| image:: https://img.shields.io/conda/pn/conda-forge/jpype1.svg .. |license| image:: https://img.shields.io/github/license/jpype-project/jpype.svg .. _Apache 2 License: https://github.com/jpype-project/jpype/blob/master/LICENSE .. _Python Docs: http://jpype.readthedocs.org/en/latest/ SPDX-License-Identifier: Apache-2.0 jpype-1.3.0/codecov.yml000066400000000000000000000011601405671516700150210ustar00rootroot00000000000000codecov: require_ci_to_pass: yes coverage: precision: 2 round: down range: "70...100" status: project: default: false python: target: 85% threshold: 1% paths: "jpype/" cpp: target: 80% threshold: 1% paths: - "native/common/" - "native/python/" java: target: 75% threshold: 2% paths: "native/java/" parsers: gcov: branch_detection: conditional: yes loop: yes method: no macro: no comment: layout: "reach,diff,flags,tree" behavior: default require_changes: no jpype-1.3.0/coverage.sh000066400000000000000000000013301405671516700150020ustar00rootroot00000000000000#!/bin/sh # Script for testing coverage locally PYTHON=python PIP="python -m pip" ./resolve.sh $PYTHON setup.py test_java $PIP install gcovr pytest-cov jedi $PYTHON setup.py --enable-coverage --enable-build-jar build_ext --inplace $PYTHON -m pytest -rsx -v test/jpypetest \ --cov-report=xml:coverage_py.xml \ --cov-report=html:build/coverage/python \ --cov=jpype \ --classpath="build/classes" --jacoco --checkjni java -jar lib/org.jacoco.cli-0.8.5-nodeps.jar report build/coverage/jacoco.exec \ --classfiles build/classes/ \ --html build/coverage/java \ --sourcefiles native/java mkdir build/coverage/cpp gcovr -r . --html-details -o build/coverage/cpp/jpype.html --exclude-unreachable-branches --exclude-throw-branches jpype-1.3.0/dev-requirements.txt000066400000000000000000000000521405671516700167130ustar00rootroot00000000000000typing-extensions ; python_version< "3.8" jpype-1.3.0/doc/000077500000000000000000000000001405671516700134235ustar00rootroot00000000000000jpype-1.3.0/doc/CHANGELOG.rst000066400000000000000000000706451405671516700154600ustar00rootroot00000000000000Changelog ========= This changelog *only* contains changes from the *first* pypi release (0.5.4.3) onwards. Latest Changes: - **1.3.0 - 2021-05-19** - Fixes for memory issues found when upgrading to Python 3.10 beta. - Add additional diagnositics for importing of non-public class. - Fixed issue with classes with unsatified dependencies leading to a crash on windows. - Fixed a bug with arrays created using the short cut. The wrong type was being returned. - **1.2.1 - 2021-01-02** - Missing stub files added. - Python 3.9 issues are resolved on Windows. - JPype scans jar files and rebuilding missing directories to allow imports from stripped and obfuscated jar files. - **1.2.0 - 2020-11-29** - Added builds for Python 3.9. Python 3.9 on Windows is currently failing due to issue in Python. - Fixed bug when importing from multi-release jars. The directory was being truncated to only those classes in the overlay. - addClassPath can add jar files after the JVM is started. The default loader for JPype class is ``org.jpype.classloader.DynamicClassLoader``. - Build support of z/OS added. - Bug causing ambiguity between primitives and variadic arguments in method resolution was corrected. - Boolean was inadvertently left out of method resolution. ``boolean`` now properly matched with boxed types. - Support for PyInstaller was added. - **1.1.2 - 2020-10-23** - Linux binaries are now stripped for size. - Add importlib.util to address instability in Python importlib boot process. Certain versions of Python such as 3.9 appear to not properly load this module resulting in unexpected errors during startJVM. - **1.1.1 - 2020-10-21** - Fixed packaging problem on linux. - **1.1.0 - 2020-10-13** - Correct bug resulting in reporting ambiguous overloads when resolving methods with variadic arguments. - Ctrl+C behavior is switchable with interrupt flag to startJVM. If True, process will halt on Ctrl-C. If False, the process will transfer control to Python rather than halting. If not specified JPype will assume false if Python is started as an interactive shell. - Fixed crash with Ctrl+C when multiple exceptions were generated. - Removed extraneous exception when calling Ctrl+C before Java code is executed for methods and fields. - Fixed memory leak with string cache. - Fixed crash when manually creating wrappers for anonymous classes. - Fixed reference count problem in stackframes used for exceptions. - Errors report `*static*` when the matching with a static method so that it is clear when a member method was called statically. - java.lang.String slices function like Python string slice. - Java packages now operate as normal Python modules. Removed restrictions regarding setattr. All package instances for the same package name are shared so that functionality added to one instance is shared wiht all instances. - **1.0.2 - 2020-07-27** - The wrapper for Throwable was getting the wrapper for Object rather than the expected wrapper resulting in odd conversions from Python classes. - Typos within the import system resulting in "jname" not found corrected. - ^C propogates to a KeyboardInterrupt properly. - Added cache to the method dispatch to bypass resolution of overloads. This reduces the cost of method resolution significantly especially if the same overload is hit repeatedly such as during loop operations. - Improved speed on transfer of lists, tuples, buffers to arrays of Java primitives by a factor of 4 to 100 depending on the data type. The conversion uses optimized path for memory buffers, rather than the Sequence API. When a Python buffer is encountered only the first element is checked for conversion as Python buffers are homogeneous. - Corrected symbol problem with Python 3.5.3. PySlice_Unpack was introduced in a later patch release and should not have been used. - **shutdown** The behavior log entry for changes on shutdown were lost in the 1.0 release. JPype now calls the JVM shutdown routine which tries to gracefully exit when shutdown is called. This results in several changes in behavior. Non daemon threads can now hold open the JVM until they have completed. Proxy calls will hold the shutdown until the call is completed but will receive an interrupt message. Files now close properly and will flush if the threads properly handle the exception. Resource clean up hooks and finalizers are executed. AtExit hooks in the JVM are called as spawned threads. Automatic attachment of threads by use of the JVM from Python are done as daemon but can be reattached as user threads on demand. Buggy code that fails to properly handle thread clean up will likely hang on shutdown. Additional documentation is located in the user guide. - A bug was reported with numpy.linalg.inv resulting in crashes. This was traced to an interaction with threading between the JVM and some compilations of numpy. The workaround appears to be calling numpy.linalg.inv prior to starting the JVM. - **1.0.1 - 2020-07-16** - Workarounds for Python 3.8.4 release. Python altered logic regarding the use of ``__setattr__`` for object and type, preventing it from being used to alter derived classes. Also the checking for errors was delegated from the ``__setattr__`` method so exception types on some sanity checks needed to be updated accordingly. - **1.0.0 - 2020-07-12** - ``JChar`` is supported as a return type, thus rather than returning a string where a ``JChar`` is expected. For compatiblity ``JChar`` is derived from ``str`` and implements implicit conversion to an ``int`` when used in numeric operations. Therefore, it passes the return, argument, and field contracts. But that means it is no longer considered a numerical type to Python and thus ``isinstance(c, int)`` is False. This is consistent with the Java type conversion rules. - Introduced Python operator for Java casting. In Java to cast to a type you would use ``(Type) obj``, but Python does not support anything similar. Therefore, we are enlisting the rarely used ``matmul`` operator as to allow an easy way to cast an object to a Java type. When a cast to a Java type is required, use ``Type@obj`` or ``(Type)@obj``. - Introduced array notation to create Java arrays. In earlier versions, JArray factory was required to make a new array type. But this is tedious to read. In Java the notation would be ``Type[]`` to declare a type or ``new Type[sz]`` to make a new array. Python does not directly support this notation, but it does allow for unspecifed array sizes using a slice. All Java class types support ``Type[sz]`` to create an array of a fixed size and ``Type[:]`` to create an array type which can be intiated later. This call be applied to multiple dimensions to create fixed sized arrays ``Type[s1][s2][s3]`` to declare multidimension array types ``Type[:][:][:]`` or to create a new multi dimensional array with unspecified dimensions ``Type[sz][:][:]``. Applying a slice with limits to a class is unsupported. - Java classes annotated with ``@FunctionalInterface`` can be converted from any Python object that implements ``__call__``. This allows functions, lambdas, and class constructors to be used whereever Java accepts a lambda. - Support for Protocol on type conversions. Attribute based conversions deprecated in favor of Protocol. Internal API for stubbing. - Deprecated class and functions were removed. ``JIterator``, use of ``JException`` as a factory, ``get_default_jvm_path``, ``jpype.reflect`` module. - Default for starting JVM is now to return Java strings rather than convert. - Python deprecated ``__int__`` so implicit conversions between float and integer types will produce a ``TypeError``. - Use of ``JException`` is discouraged. To catch all exceptions or test if an object is a Java exception type, use ``java.lang.Throwable``. - Chained Java exception causes are now reflected in the Python stackframes. - Use of ``JString`` is discouraged. To create a Java string or test if an object is a Java string type, use ``java.lang.String``. - Updated the repr methods on Java classes. - ``java.util.List`` completes the contract for ``collections.abc.Sequence`` and ``collections.abc.MutableSequence``. - ``java.util.Collection`` completes the contract for ``collections.abc.Collection``. - Java classes are closed and will raise ``TypeError`` if extended in Python. - Handles Control-C gracefully. Previous versions crash whenever Java handles the Control-C signal as they would shutdown Java during a call. Now JPype will produce a ``InterruptedException`` when returning from Java. Control-C will not break out of large Java procedures as currently implemented as Java does not have a specific provision for this. - **0.7.5 - 2020-05-10** - Updated docs. - Fix corrupt conda release. - **0.7.4 - 4-28-2020** - Corrected a resource leak in arrays that affects array initialization, and variable argument methods. - Upgraded diagnostic tracing and JNI checks to prevent future resource leaks. - **0.7.3 - 4-17-2020** - **Replaced type management system**, memory management for internal classes is now completely in Java to allow enhancements for buffer support and revised type conversion system. - Python module ``jpype.reflect`` will be removed in the next release. - ``jpype.startJVM`` option ``convertStrings`` default will become False in the next release. - Undocumented feature of using a Python type in ``JObject(obj, type=tp)`` is deprecated to support casting to Python wrapper types in Java in a future release. - Dropped support for Cygwin platform. - ``JFloat`` properly follows Java rules for conversion from ``JDouble``. Floats outside of range map to inf and -inf. - ``java.lang.Number`` converts automatically from Python and Java numbers. Java primitive types will cast to their proper box type when passed to methods and fields taking Number. - ``java.lang.Object`` and ``java.lang.Number`` box signed, sized numpy types (int8, int16, int32, int64, float32, float64) to the Java boxed type with the same size automatically. Architecture dependent numpy types map to Long or Double like other Python types. - Explicit casting using primitives such as JInt will not produce an ``OverflowError``. Implicit casting from Python types such as int or float will. - Returns for number type primitives will retain their return type information. These are derived from Python ``int`` and ``float`` types thus no change in behavior unless chaining from a Java methods which is not allowed in Java without a cast. ``JBoolean`` and ``JChar`` still produce Python types only. - Add support for direct conversion of multi-dimensional primitive arrays with ``JArray.of(array, [dtype=type])`` - ``java.nio.Buffer`` derived objects can convert to memoryview if they are direct. They can be converted to NumPy arrays with ``numpy.asarray(memoryview(obj))``. - Proxies created with ``@JImplements`` properly implement ``toString``, ``hashCode``, and ``equals``. - Proxies pass Python exceptions properly rather converting to ``java.lang.RuntimeException`` - ``JProxy.unwrap()`` will return the original instance object for proxies created with JProxy. Otherwise will return the proxy. - JProxy instances created with the ``convert=True`` argument will automatic unwrap when passed from Java to Python. - JProxy only creates one copy of the invocation handler per garbage collection rather than once per use. Thus proxy objects placed in memory containers will have the same object id so long as Java holds on to it. - jpype.imports and JPackage verify existance of packages and classes. Imports from Java packages support wildcards. - Bug with JPackage that imported private and protected classes inappropriately has been corrected. Protected classes can still be imported using JClass. - Undocumented feature of using a Python type in ``JObject(obj, type=tp)`` is deprecated to support casting to Python wrapper types in Java in a - ``@JImplements`` with keyword argument ``deferred`` can be started prior to starting the JVM. Methods are checked at first object creation. - Fix bug that was causing ``java.lang.Comparable``, ``byte[]``, and ``char[]`` to be unhashable. - Fix bug causing segfault when throwing Exceptions which lack a default constructor. - Fixed segfault when methods called by proxy have incorrect number of arguments. - Fixed stack overflow crash on iterating ImmutableList - ``java.util.Map`` conforms to Python ``collections.abc.Mapping`` API. - ``java.lang.ArrayIndexOutOfBoundsException`` can be caught with ``IndexError`` for consistency with Python exception usage. - ``java.lang.NullPointerException`` can be caught with ``ValueError`` for consistency with Python exception usage. - **Replaced type conversion system**, type conversions test conversion once per type improving speed and increasing flexiblity. - User defined implicit conversions can be created with ``@JConversion`` decorator on Python function taking Java class and Python object. Converter function must produce a Java class instance. - ``pathlib.Path`` can be implicitly converted into ``java.lang.File`` and ``java.lang.Path``. - ``datetime.datatime`` can implicitly convert to ``java.time.Instant``. - ``dict`` and ``collections.abc.Mapping`` can convert to ``java.util.Map`` if all element are convertable to Java. Otherwise, ``TypeError`` is raised. - ``list`` and ``collections.abc.Sequence`` can convert to ``java.util.Collection`` if all elements are convertable to Java. Otherwise, ``TypeError`` is raised. - **0.7.2 - 2-28-2020** - C++ and Java exceptions hold the traceback as a Python exception cause. It is no longer necessary to call stacktrace() to retrieve the traceback information. - Speed for call return path has been improved by a factor of 3. - Multidimensional array buffer transfers increase speed transfers to numpy substantially (orders of magnitude). Multidimension primitive transfers are read-only copies produced inside the JVM with C contiguous layout. - All exposed internals have been replaced with CPython implementations thus symbols `__javaclass__`, `__javavalue__`, and `__javaproxy__` have been removed. A dedicated Java slot has been added to all CPython types derived from `_jpype` class types. All private tables have been moved to CPython. Java types must derive from the metaclass `JClass` which enforces type slots. Mixins of Python base classes is not permitted. Objects, Proxies, Exceptions, Numbers, and Arrays derive directly from internal CPython implementations. See the :doc:`ChangeLog-0.7.2` for details of all changes. - Internal improvements to tracing and exception handling. - Memory leak in convertToDirectBuffer has been corrected. = Arrays slices are now a view which support writeback to the original like numpy array. Array slices are no longer covariant returns of list or numpy.array depending on the build procedure. - Array slices support steps for both set and get. - Arrays now implement `__reversed__` - Incorrect mapping of floats between 0 and 1 to False in setting Java boolean array members is corrected. - Java arrays now properly assert range checks when setting elements from sequences. - Java arrays support memoryview API and no longer required NumPy to transfer buffer contents. - Numpy is no longer an optional extra. Memory transfer to NumPy is available without compiling for numpy support. - JInterface is now a meta class. Use ``isinstance(cls, JInterface)`` to test for interfaces. - Fixed memory leak in Proxy invocation - Fixed bug with Proxy not converting when passed as an argument to Python functions during execution of proxies - Missing tlds "mil", "net", and "edu" added to default imports. - Enhanced error reporting for UnsupportedClassVersion during startup. - Corrections for collection methods to improve complience with Python containers. - java.util.Map gives KeyError if the item is not found. Values that are ``null`` still return ``None`` as expected. Use ``get()`` if empty keys are to be treated as ``None``. - java.util.Collection ``__delitem__`` was removed as it overloads oddly between ``remove(Object)`` and ``remove(int)`` on Lists. Use Java ``remove()`` method to access the original Java behavior, but a cast is strongly recommended to to handle the overload. - java.lang.IndexOutOfBoundsException can be caught with IndexError for complience when accessing ``java.util.List`` elements. - **0.7.1 - 12-16-2019** - Updated the keyword safe list for Python 3. - Automatic conversion of CharSequence from Python strings. - java.lang.AutoCloseable supports Python "with" statement. - Hash codes for boxed types work properly in Python 3 and can be used as dictionary keys again (same as JPype 0.6). Java arrays have working hash codes, but as they are mutable should not be used as dictionary keys. java.lang.Character, java.lang.Float, and java.lang.Double all work as dictionary keys, but due to differences in the hashing algorithm do not index to the same location as Python native types and thus may cause issues when used as dictionary keys. - Updated getJVMVersion to work with JDK 9+. - Added support for pickling of Java objects using optional module ``jpype.pickle`` - Fixed incorrect string conversion on exceptions. `str()` was incorrectly returning `getMessage` rather than `toString`. - Fixed an issue with JDK 12 regarding calling methods with reflection. - Removed limitations having to do with CallerSensitive methods. Methods affected are listed in :doc:`caller_sensitive`. Caller sensitive methods now receive an internal JPype class as the caller - Fixed segfault when converting null elements while accessing a slice from a Java object array. - PyJPMethod now supports the FunctionType API. - Tab completion with Jedi is supported. Jedi is the engine behind tab completion in many popular editors and shells such as IPython. Jedi version 0.14.1 is required for tab completion as earlier versions did not support annotations on compiled classes. Tab completion with older versions requires use of the IPython greedy method. - JProxy objects now are returned from Java as the Python objects that originate from. Older style proxy classes return the inst or dict. New style return the proxy class instance. Thus proxy classes can be stored on generic Java containers and retrieved as Python objects. - **0.7.0 - 2019** - Doc strings are generated for classes and methods. - Complete rewrite of the core module code to deal unattached threads, improved hardening, and member management. Massive number of internal bugs were identified during the rewrite and corrected. See the :doc:`ChangeLog-0.7` for details of all changes. - API breakage: - Java strings conversion behavior has changed. The previous behavior was switchable, but only the default convert to Python was working. Converting to automatically lead to problems in which is was impossible to work with classes like StringBuilder in Java. To convert a Java string use ``str()``. Therefore, string conversion is currently selected by a switch at the start of the JVM. The default shall be False starting in JPype 0.8. New code is encouraged to use the future default of False. For the transition period the default will be True with a warning if not policy was selected to encourage developers to pick the string conversion policy that best applies to their application. - Java exceptions are now derived from Python exception. The old wrapper types have been removed. Catch the exception with the actual Java exception type rather than ``JException``. - Undocumented exceptions issued from within JPype have been mapped to the corresponding Python exception types such as ``TypeError`` and ``ValueError`` appropriately. Code catching exceptions from previous versions should be checked to make sure all exception paths are being handled. - Undocumented property import of Java bean pattern get/set accessors was removed as the default. It is available with ``import jpype.beans``, but its use is discouraged. - API rework: - JPype factory methods now act as base classes for dynamic class trees. - Static fields and methods are now available in object instances. - Inner classes are now imported with the parent class. - ``jpype.imports`` works with Python 2.7. - Proxies and customizers now use decorators rather than exposing internal classes. Existing ``JProxy`` code still works. - Decorator style proxies use ``@JImplements`` and ``@JOverload`` to create proxies from regular classes. - Decorator style customizers use ``@JImplementionFor`` - Module ``jpype.types`` was introduced containing only the Java type wrappers. Use ``from jpype.types import *`` to pull in this subset of JPype. - ``synchronized`` using the Python ``with`` statement now works for locking of Java objects. - Previous bug in initialization of arrays from list has been corrected. - Added extra verbiage to the to the raised exception when an overloaded method could not be matched. It now prints a list of all possible method signatures. - The following is now DEPRECATED - ``jpype.reflect.*`` - All class information is available with ``.class_`` - Unncessary ``JException`` from string now issues a warning. - The followind is now REMOVED - Python thread option for ``JPypeReferenceQueue``. References are always handled with with the Java cleanup routine. The undocumented ``setUsePythonThreadForDaemon()`` has been removed. - Undocumented switch to change strings from automatic to manual conversion has been removed. - Artifical base classes ``JavaClass`` and ``JavaObject`` have been removed. - Undocumented old style customizers have been removed. - Many internal jpype symbols have been removed from the namespace to prevent leakage of symbols on imports. - promoted *`--install-option`* to a *`--global-option`* as it applies to the build as well as install. - Added *`--enable-tracing`* to setup.py to allow for compiling with tracing for debugging. - Ant is required to build jpype from source, use ``--ant=`` with setup.py to direct to a specific ant. - **0.6.3 - 2018-04-03** - Java reference counting has been converted to use JNI PushLocalFrame/PopLocalFrame. Several resource leaks were removed. - ``java.lang.Class<>.forName()`` will now return the java.lang.Class. Work arounds for requiring the class loader are no longer needed. Customizers now support customization of static members. - Support of ``java.lang.Class<>`` - ``java.lang.Object().getClass()`` on Java objects returns a java.lang.Class rather than the Python class - ``java.lang.Object().__class__`` on Java objects returns the python class as do all python objects - ``java.lang.Object.class_`` maps to the java statement ``java.lang.Object.class`` and returns the ``java.lang.Class`` - java.lang.Class supports reflection methods - private fields and methods can be accessed via reflection - annotations are avaiable via reflection - Java objects and arrays will not accept setattr unless the attribute corresponds to a java method or field whith the exception of private attributes that begin with underscore. - Added support for automatic conversion of boxed types. - Boxed types automatically convert to python primitives. - Boxed types automatically convert to java primitives when resolving functions. - Functions taking boxed or primitives still resolve based on closest match. - Python integer primitives will implicitly match java float and double as per Java specification. - Added support for try with resources for ``java.lang.Closeable``. Use python "with MyJavaResource() as resource:" statement to automatically close a resource at the end of a block. - **0.6.2 - 2017-01-13** - Fix JVM location for OSX. - Fix a method overload bug. - Add support for synthetic methods - **0.6.1 - 2015-08-05** - Fix proxy with arguments issue. - Fix Python 3 support for Windows failing to import winreg. - Fix non matching overloads on iterating java collections. - **0.6.0 - 2015-04-13** - Python3 support. - Fix OutOfMemoryError. - **0.5.7 - 2014-10-29** - No JDK/JRE is required to build anymore due to provided jni.h. To override this, one needs to set a JAVA_HOME pointing to a JDK during setup. - Better support for various platforms and compilers (MinGW, Cygwin, Windows) - **0.5.6 - 2014-09-27** - *Note*: In this release we returned to the three point number versioning scheme. - Fix #63: 'property' object has no attribute 'isBeanMutator' - Fix #70: python setup.py develop does now work as expected - Fix #79, Fix #85: missing declaration of 'uint' - Fix #80: opt out NumPy code dependency by '--disable-numpy' parameter to setup. To opt out with pip append --install-option="--disable-numpy". - Use JVMFinder method of @tcalmant to locate a Java runtime - **0.5.5.4 - 2014-08-12** - Fix: compile issue, if numpy is not available (NPY_BOOL n/a). Closes #77 - **0.5.5.3 - 2014-08-11** - Optional support for NumPy arrays in handling of Java arrays. Both set and get slice operators are supported. Speed improvement of factor 10 for setting and factor 6 for getting. The returned arrays are typed with the matching NumPy type. - Fix: add missing wrapper type 'JShort' - Fix: Conversion check for unsigned types did not work in array setters (tautological compare) - **0.5.5.2 - 2014-04-29** - Fix: array setter memory leak (ISSUE: #64) - **0.5.5.1 - 2014-04-11** - Fix: setup.py now runs under MacOSX with Python 2.6 (referred to missing subprocess function) - **0.5.5 - 2014-04-11** - *Note* that this release is *not* compatible with Python 2.5 anymore! - Added AHL changes * replaced Python set type usage with new 2.6.x and higher * fixed broken Python slicing semantics on JArray objects * fixed a memory leak in the JVM when passing Python lists to JArray constructors * prevent ctrl+c seg faulting * corrected new[]/delete pairs to stop valgrind complaining * ship basic PyMemoryView implementation (based on numpy's) for Python 2.6 compatibility - Fast sliced access for primitive datatype arrays (factor of 10) - Use setter for Java bean property assignment even if not having a getter by @baztian - Fix public methods not being accessible if a Java bean property with the same name exists by @baztian (*Warning*: In rare cases this change is incompatibile to previous releases. If you are accessing a bean property without using the get/set method and the bean has a public method with the property's name you have to change the code to use the get/set methods.) - Make jpype.JException catch exceptions from subclasses by @baztian - Make more complex overloaded Java methods accessible (fixes https://sourceforge.net/p/jpype/bugs/69/) by @baztian and anonymous - Some minor improvements inferring unnecessary copies in extension code - Some JNI cleanups related to memory - Fix memory leak in array setters - Fix memory leak in typemanager - Add userguide from sourceforge project by @baztian - **0.5.4.5 - 2013-08-25** - Added support for OSX 10.9 Mavericks by @rmangino (#16) - **0.5.4.4 - 2013-08-10** - Rewritten Java Home directory Search by @marsam (#13, #12 and #7) - Stylistic cleanups of setup.py - **0.5.4.3 - 2013-07-27** - Initial pypi release with most fixes for easier installation jpype-1.3.0/doc/ChangeLog-0.7.2.rst000066400000000000000000000571451405671516700164620ustar00rootroot00000000000000:orphan: Buffers and NumPy removal ========================= NumPy was used primarily for supplying Python buffers on slicing. Numpy has always been problematic for JPype. As an optional extra is may or may not be built into the distribution, but if it is compiled in it is required. Therefore, is itn't really on "extra". Therefore, removing it would make distribution for binary versions of JPype much easier. NumPy returns on slicing is but one part of the three uses of Python buffers in JPype. Thus to properly remove it we need to rework to remove it we need to review all three of the paths. These paths are - Conversion of Python buffers to Java arrays on setArrayRange. - Conversion of Java arrays to slices (and then from slices to buffers so that they can be transferred to NumPy.) - Connecting bytearray to Java direct byte buffers. We reviewed and revised each of the paths accordingly. On conversion of Python buffers, the implementation was dated from Python 2.6 era where there was no formal support for buffers. Thus the buffer implementation never consulted the buffer type to see what type of object was being transferred nor how the memory was oriented. This entire section had to be replaced and was given the same conversion rules as NumPy. Any conversion is possible (including lossy ones like float to bool). The rules to trigger the conversion is by slicing just as with NumPy. By replicating the rules of NumPy we hide the fact that NumPy is no longer used and increase typesafety. There was a number of cases where in the past it would reinterpret cast the memory that will now function properly. The old behavior was a useless side effect of the implementation and was unstable with machine architecture so not likely used be a user. The getArrayRange portion has to be split into two pieces. Under the previous implementation the type of the return changes from Python list to NumPy array depending on the compile option. Thus the test suite tested different behaviors for each. In removing NumPy we replace the Java array slice return with a Java array. Thus the type is always consistent. The Java array that is returned is still backed by the same array as before and has the start, end, and step set appropriately. This does create one change in behavior as the slice now has left assignment (just like NumPy) and before it was a copy. It is difficult exercise this but to do so we have to copy a slice to a new variable then use a second array dereference to assign an element. Because we converted to either list or NumPy, the second dereference could not affect the original. There is no way to avoid this behavior change without adding a large transaction cost. Which is why NumPy has the exact same behavior as our replacement implementation. We could in principle make the slice read only rather than allowing for double slicing, but that would also be an API change. There is one other consequence of producing a view of the original having to do with passing back to Java. As Java does not recognize the concept of an array view we must force it back to a Java type at the JNI level. We will force copy the array slice into a Java array at that time. Thus replicates the same functionality. This induces one special edge case as `java.lang.Object` and `java.lang.Serializable` which are both implemented by arrays must be aware of the slice copy. Before we trigger the conversion to NumPy or list by calling the slice without limits operator `[:]` on the array. Under the new implementation this is effectively a no-op. Thus we haven't broken or forced any changes in the API. The third case of direct byte buffers also revealed problems. Again the type of the buffer was not being check resulting in weird reinterpret cast like behaviors. Additionally, the memory buffer interface was making a very bad assumption about the referencing of the buffer by assuming that referencing the object that holds the buffer is the same as referencing the buffer itself. It was working only because the buffer was being leaked entirely and was likely possible to break under situations as the leaked buffer essentially locked the object forever. To implement all of this properly unfortunately requires making the Python wrapper of Java arrays a direct type. This is possible in JPype 0.8 series where we converted all classes to CPython roots, thus our only choice is to backport the JPype speed patch into JPype 0.7. API change summary ------------------ - The type of a slice is no longer polymorphic but is always a Java array now. - The unbounded slice is now a no op. - Buffer types now trigger conversion routines rather than reinterpret casting the memory. - Direct buffers now guard the memory layout such that they work only with mutable bytearray like types. - Assignment of elements though double slicing of an array now affects the original rather than just doing nothing effective like before. JPype Speed Patch ================= Speed has always been an issue for JPype. While the interface of JPype is great the underlying implementation is wanting. Part of this was choices made early in the development that favors ease of implementation over speed. This forced a very thin interface using Python capsules and then the majority of the code in a pure Python module. The speed issue stems from two main paths. The first being the method resolution phase in which we need to consider each method overload argument by argument which means many queries applied to each object. The second is the object construction penality when we return a Java object back to Python. The object bottleneck is both on the cost of the wrappers we produce, but additionaly all of the objects that are constructed to communicate with a Python function. Every int, list, string and tuple we use in the process is another object to construct. Thus returning one object triggers dozens of object to be constructed. We have addressed these problems in five ways - Improve resolution of methods by removing the two phase approach to resolving a type match cutting the resolution time in half. - Caching the types in C so that they don't have to go back to Python to execute a method to check the Python cache and construct if necessary. - Converting all of the base types to CPython so that they can directly access the C++ guts without going back through entry points. - Remove all Python new and init method from the Java class tree so that we don't leave C during the construction phase. Thus avoiding having to construct Python objects for each argument used during object construction. - Adding a Java slot to so that we can directly access Java resources both increasing the speed of the queries and saving us an additional object during construction. All of these are being implemented for JPype 0.8 series. For now we are backporting the last four to the JPype 0.7 series. The first is not possible to backport as it requires larger structural changes. Lets briefly discuss each of the items Method resolution ----------------- During method resolution the previous implementation had a two phase approach. First is tried to match the arguments to the Java types in canConvertToJava. In this each Java argument had to walk through each possible type conversion and decide if the conversion is possible. Once the we have the method overload resovled we then perform the conversion by calling convertToJava. That would then walk through each possible type conversion to find the right one and apply it. Thus we did tha work twice. To prevent this from happening we need to reserve memory for each argument we are trying to convert. When we walk through the list and find a conversion rather than just returning true, we place a pointer to the conversion routine. That way when we call convertToJava we don't have to walk the list a second time but instead go straight to the pointer to get the routine to execute. This change has two additional consequences. First the primary source of bugs in the type conversion was a mismatch between canConvertToJava and convertToJava thus we are removing that problem entirely. The second and more important to the user is that the type system is now open. By installing a routine we can now add a user rule. Therefore if we need `java.sql.TimeStamp` to accept a Python time object we just need to add this to the type conversion table at the Python level. This is implemented in the ClassHints patch. About half of our customizer code was to try to achieve this on a per method level. Thus this elimiates a lot of our current Python customizer code. The remaining customizer code is to rename Java methods to Python methods and that will remain. Caching of Python wrappers -------------------------- In the previous implementation there was a text keyed dictionary that was consulted to get type wrappers. To access it C++ called to a Python function that decided when to return a cached type and when to create a new one. This meant dozens of object constructed just to find the wrapper. To solve this we simply move the cache and add it to the JClass directly. We have to back reference the Python class so it can't go away while the JVM is running. There is one section of code that also uses the wrapper dict in the customizers which needs to decided does a wrapper already exist for the customizer. We have replaced these calls with methods on the module. Conversion of the Base classes ------------------------------ JPype has a number of base classes (object, primitive, exception, string, array) which hold the methods for the class. If they are implemented as pure Python than every access from C++ to these elements needs to create objects accordingly when then are passed back through the module entry points to get back to C++. We can avoid this by implementing each of these in CPython first at the module layer and then extending them in the exposed module so that they have the same outward appearance as before. We made one refinement during the conversion by implementing all of the CPython classes using the Heep type API which has the distinct advantage that unlike static types, it can be changed at runtime. Thus from Python we can add behavior to the heap types simply with by using `type.__setattr_`. This was a bit of a challenge as the documentation on heap types is much more sparse than for static types. However, after going through the process I would recommend that all new CPython modules should use heap types rather than static as API is much better and the result much more flexable and stable. The only downside being the memory footprint increases from 400 bytes to 900 bytes. There are a few rough spots in the heap type API in that certain actions like setting the Buffer have to be added to the type after creation, but otherwise it is a big improvement. Now if all of the documentation would just drop the old static API in favor of heap types it would be great. Constructor simplifications --------------------------- In order to benefit from moving all of the base classes to C, we have to make sure that derived classes do not transfer control back to Python. Currently this happens due to the factory nature of our classes. The entry point for JObject is shared between the construction of objects from Python and a return from Java. Thus we have to either separate the factory behavior by pushing those types out of the type tree or pushing the factory behavior into the C layer. We have chosen to split the factories and use overrides of the type system in the meta class to apply `isinstance` and `issubtype` behavior. We can further restrict the type system if we need to by adding verifications that the `__new__` and `__init__` methods must point the original base class implementations if need. Howver, we have not taken this step as of yet. The split approach effectively removes these heavy elements from type creation. The concequence of this is that means all of the rest of logic needs to be in CPython implementation. These can be rather cumbersome at times. It is always a slippery slope when pushing code from Python back to CPython. Some thing are needed as they are on the critical path while others are called only occasionally and thus represent no cost to leave in Python. On the other hand some things are easy to implement in CPython because the have direct access rather than having to go through a module entry point. We have gone with the approach that all critical path and all code the eliminates the need for an entry point should be pushed back to C. Java Slots ------------- In order to get any reasonable speed with Python, the majority of the code needs to be in C. But additionally there needs to be the use of slots which are hard coded locations to search for a particular piece of information. This presents a challenge when wrapping Java as we need a slot for the Java value structure which must appear on Python object, long, float, exception, and type. These different types each have their own memory layout and thus we can't just add the slot at the base as once something is added to the base object it can no longer be used in multiple inheritance. Thus we require a different approach. Looking through the CPython source, we find they have the same quandary with respect to `__dict__` and `__weakref__` slots. Those slots do not appear one the base object but get added along the way. The method they use is to add those slots to the back of the object be increasing the basesize of the object and then referencing them with two offset slots in the type object. If the type is variable length the slot offset are negative thus referencing from the end of the object, or positive if the object is a fixed layout. Thus we tried a few formulations to see what would work best. Broken tree approach ~~~~~~~~~~~~~~~~~~~~ The problem with just directly adding the slots in the tree is that the Java inheritance tree forces the order of the Python tree we have to apply. If we add a slot to `java.lang.Object` we have to keep the slot on `java.lang.Throwable` but that is not possible because Throwable requires it to be derived from Python `Exception`. Thus if we are going to add a slot to the base we would have to break the tree into pieces on the Python side. This is possible due to Python inheritance hacking with some effort. But this approach had significant down sides. When we go to access the slot we have to first figure out if the slot is present and if not then fall back to looking in the dictionary. But one of the most common cases is one in which the item has no slot at all. Thus if we have to both look for the slot and then hit the dictionary, this is worse than just going to the dictionary in the first place. Thus this defeats the point of a slot in many cases. Python dict approach ~~~~~~~~~~~~~~~~~~~~~~~~~ We attempted the same trick by increasing the basesize to account for our extra slot. This leaves to difficulties. First, the slot has no offset so we need to find it each time by implying its location. Second, the extra objects have to be "invisible" during the type construction phase, or Python will conclude the memory layout of the object is in conflict. We can fool the type system by subtracting the extra space from the type during the declaration phase and then adding it back after the base types are created. This approach failed because the "invisible" part is checked each and every time a new type is added to the system. Thus every dynamic type we add checks the base types for consistency and at some point the type system will find the inconsistency and cause a failure. Therefore, this system can never be robust. Dict and weakref appear to be very special cases within the Python system and as there is no general facility to replicate them working within the system does not appear to be viable. Memory hacking approach ~~~~~~~~~~~~~~~~~~~~~~~ The last system we attempted to mess with the memory layout of the object during the creation phase to append our memory after Pythons. To do this we need to override the memory allocator to allocate the requested memory plus our extra. We can then access this appended memory by computing the correct size of the object and thus our slot is on the end. We can test if the slot is present by looking to see if both `tp_alloc` and `tp_finalize` point to our Java slot handlers. This means we are still effectively a slot as we can test and access with O(1). The downside of this approach is there are certain cases in which the type of an object can be changed during the destruction phase which means that our slot can point to the wrong space if the basesize is changed out from under us. To guard against this we need to close our type system by imposing a ClassMeta which closes off mixin types that do not inherit from one of the special case base classes we have defined. The API implications should be small. There was never a functional case where extending a Java object within Python actually made sense as the Python portion is just lost when passed to Java and unlike Proxies there is no way to retrieve it. Further the extending a Java object within Python does not bind the lifespan of the objects so any code that used this is likely already buggy. We will properly support this option with `@JExtends` at a latter point. With this limitiation in mind, this appears to be the best implementation - It adds the slot to all of the required types. - The slot is immediately accessable using just two fields (basesize, itemsize) - The slot can be tested for easily (check tp_alloc, tp_finalize) - It closes the type system by forcing a meta class that guards against inappropraite class constuction. We could in principle add the slot to the "front" of the Python object but that could cause additional issues as we would require also require overriding the deallocation slot to disappear our memory from the free. The Python GC module has already reserved the memory in the front of the object so the back is the next best option. Speed patch implications ------------------------ Other than improving the speed, the speed patch has a lot of below the hood changes. So long as the user was not accessing private members there is no API change, but everything below that is gone. All private symbols like `__javaclass__` and `__javavalue__` as well as all exposed private members vanish from the interface. There is no longer a distinction between class wrappers and `java.lang.Class` instances for purposes of the casting system. The wrapper is an extension of a Python type and has the class methods and fields, and the instance is an extension of a Python object without these. Both hold Java slots to the same object. Therefore a lot of complexity of the private portions is effectively removed from the user view. Every path now has the same resolution, check the Java slot first and if not assume it is Python. Two private methods now appear on the wrapper (though I may be able to hide them from the user view.) These are the test entry points `_canConvertToJava` and `_convertToJava`. Thus the speed patch should be transparent all user code that does not access our private members. That said some code like the Database wrappers using JPype have roots in some code that did make access to the private tables. I have sent corrections when we upgraded to 0.7 series thus making them conforming enough not to touch the private members. But that does mean some modules may be making such accesses out in the wild. The good new is after the speed patch pretty much everything that is supposed to be under the hood is now out of the reach of the user. Thus the chance of future API breakage is much lower. Below the hood changes ====================== - We have tried to prevent backend changes from reaching the API, though this is not always entirely the case. The majority of the cases not already noted appear to be in the range of implementation side effects. The old implementation had bugs that create undefined behaviors like reinterpet casting buffers and the like. It is not possible to both fix the bugs in the backend and make preserve buggy behavours on the front end. We have limited our changes to only those for which we can see no desirable use existing. Calling a list slice assignment on a float from a numpy array of ints and getting a pile of gibberish was as far as we can tell not useful to the user. - setResource is dropped in favor of caching the module dictionary once at start of the JVM. We have a lot of resources we will need and the setResources method was cumbersome. - There is a lot of thrashing for the Python module style between C and C++ style. The determining blow was that C++ exception warning showed up when the proper linkage was given. Thus the perferred style flipped from C++ style to C. Thus the naming style change accordingly. - In addition to the style change there is also an attempt to isolate symbols between the different classes. The older style with a formal header that declares all the symbols at the top encouraged access to the functions and increased the complexity. Moving to a C style and making everything static forces the classes to be much more independent. - With the change to C style there is natural split in CPython class files between the structure declaration, static methods that implement Python API functions, the declaration of the type, and the exposed C++ style API used by the rest of the module. - There is some thrashing on how much of the C++ wrapper style Python API to keep. The rewrapping of the API was mainly so support differences between Python 2.7 and 3.x. So we dropped where we could. Only the JPPyObject which acts as memory handling device over pure Python style (because Python style is not exception safe) is strongly needed. - There is some spacing thrashing between different editors and the continuing debate of why C was written to have the pointer stick to to the variable rather than the type. When writing `Object* foo` it implies that the star is stuck to type rather than the variable where C reads it as the opposite. Hence there is the endless churn between what is correct `Object *foo` and what we would say in which `Object*` is actually a type. As Python favors the former and we currently have the latter that means at some point we should just have formatter force consistency. - We introduced Py_IsInstanceSingle. Is is a missing Python API function first for fast type check method of a single inherited type using the mro. Then something is singlely inherited we can bypass the whole pile of redirects and list searchs and just compare if the mro list matches at the same point counted from the end. As all of our base types are single inherited this saves time and dodges the more expensive calls that would trigger due to the PyJPClassMeta overrides. - We introduced Py_GetAttrDescriptor. This was previously implemented in Python and was very slow. Python has very good implementations for GetAttr but unfortunately it has the behavior that it always dereferences descriptors. Thus it is useless in the case that we need to get the descriptor from the type tree. We have reimplemented the Python type search without the descriptor dereferencing behavior. It is not nearly as complete as the Python method as we only need to consult the dictionary and not handle every edge case. That of course means that we are much faster. - As with every rewrite there is the need to cleanup. Anything that wasn't reached by the test bench or was identified as being called only from one location was removed or reencorperated back in into the function that call it. jpype-1.3.0/doc/ChangeLog-0.7.rst000066400000000000000000000546141405671516700163200ustar00rootroot00000000000000:orphan: JPype 0.7 Core ChangeLog ======================== Here is the "complete" log of the changes I think I made. Module changes -------------- * Moved Python module objects to namespace ``PyJP`` so that they are consistent with a Python module namespace. Renamed module classes presented to ``_jpype`` extension to ``PyJP*`` to match the internal classes. Though not exactly a standard convention, the types were internal anyway and having the names match the C structure makes it more clear what resource is being accessed. It also eliminates the confusion between ``jpype`` and ``_jpype`` resources. * Removed all usage of Capsule from the extension module. This was bridging between Python versions and had to be replicated on old platforms. As the capsules were functioning as crippled objects, they could not have methods of their own. Thus functionality that properly belonged to a specific class would get pushed to the base class. This affected former capsules of ``JPObject``, ``JPProxy``, and ``JPArray``. These are now formal classes in the module as ``PyJPValue``, ``PyJPProxy``, and ``PyJPArray``. * Moved the initialization of each class to the ``__init__`` function. Thus rather than creating the resource at the top level ``_jpype`` module (such as ``_jpype.findClass('cls'))``, the resource is created by allocating a new object (such as ``_jpype.PyJPClass('cls')``). * The presentation of ``JPArrayClass`` has been merged as a generic ``JPClass``. The only requirement for creation of an array instance is that the supplied ``PyJPClass`` satisfy ``isArray()``. * Removed direct dependencies that objects holding resource be exactly the type in ``jpype`` module. This reduces the restrictions in the underlying Python layer and allows for multiple classes such as ``JavaArray``, ``JWrapper``, and ``JavaClass`` to all be recognized as holding resources. This simplifies some paths in the ``jpype`` module where we needed to simply access a single method during bootstrapping and we were forced to construct complete classes necessitating the order of resource loading. * Remove ``JPObject`` concept and replaced it with ``JPValue``. ``JPValue`` holds the type of the object and a ``jvalue`` union. Both ``JavaClass`` and ``JWrapper`` now point to these classes as ``__javavalue__``. Anything with a ``__javavalue__`` with type ``_jpype.PyJPValue`` is now recognized as being a Java object. * Changed the recognization of a ``JavaClass`` to any object holding ``__javaclass__`` with type ``_jpype.PyJPClass``. This allows array classes, object classes, and wrappers classes to be used together. * Added hooks to direct convert ``PyJPClass`` to a ``PyJPValue`` with a type of ``java.lang.class`` and an object to the class. This replaces the need for calling ``forName`` to get to the existing class. * Changed ``PyJPField`` and ``PyJPMethod`` to descriptors so that we do not need to mess with ``__getattribute__`` and ``__setattr__`` in many places. * Eliminated the unnecessary class bound method. C++ Reorg ~~~~~~~~~ * Reorganized the type tree in the C++ layer to better match the Java structures. * Flattened out the redundant layers so that ``JPType`` is now ``JPClass`` corresponding to an instance of a ``jclass``. * ``JPClass`` is not the base class. Arrays are now objects and have base classes and methods. * Split ``JPClass`` into a separate type for each specialized object class for boxed, ``java.lang.Object``, and ``java.lang.Class`` which all required specialized conversion rules. * Boxed, string, base ``java.lang.Object`` and base ``java.lang.Class`` are now specialized with their required conversion rules. Path reduction ~~~~~~~~~~~~~~ * Removed ``HostRef`` and all of its usage. It was a halfway memory management method. To be passed around it was being held as a dynamically allocated pointer type with no static presence for cleanup. This defeats the point of having a smart point wrapper if the smart pointer is being used as a pointer itself. Thus it was only as safe as the user applied conventions rather than safe by design. * Replaced all the ``HostRef`` methods and ``JPy*`` Python object wrappers with a new smart pointer concept (namespace ``JPPy``). This removes the redundant host and ``JPy*`` wrapper layers. * Removed multiple optimization paths such as bypassing between ``jchar`` and ``unicode`` if the size matched. These paths were for speed reasons, but they could only be tested on particular machines. Thus it was difficult to tell if something was broken. It is better to have one tested code path that is slight slower, then a faster path that is busted. * Removed dead class ``JPCharString``. * **(bug)** Replaced all string handling with conversion through UTF8. Java and Python use different UTF8 encodings and thus those paths that were trying to short cut directly through from one system to another were badly flawed. By forcing a conversion to and from each time a Java string or Python string are passed eliminates conversion problems. This should resolve user issues having to do with truncating extended unicode characters. * Combined all code paths in ``canConvertToJava`` and ``convertToJava`` to use the ``JPValue`` * Combined code paths from ``check`` and ``get`` for ``JPValue``, ``JPClass`` and ``JPProxy`` ``get`` patterns when fetching from Python. Almost always we want to use the object immediately and just check if we can. * Removed the entirely redundant Primitive type ``setRange`` and ``getRange``. That code was entirely dead because it could not be reached. Renamed the direct methods as they now have the same function. * Removed ``JPTypeName``. This concept will be phased out to support lambdas. ``TypeManager`` now used ``getCanonicalName()``. Transferred responsibility for conversion to native names to Python module interface. * Introduced named classes for all specialized instances of classes to be held in ``TypeManager`` namespace. Thus converted most of the "is this type" to comparison of ``JPClass*`` pointers in place of string level comparisons. * Removed near duplicate methods. ``JProxy`` was requesting slightly altered copies of many conversions to support its usage. These operations could be supported by just splitting to two existing methods. Thus we could eliminate a lot of stray methods that served this specialized purpose. * ``JPArray`` is now a method holder rather than the primary object like ``JPBoundMethod``. All array objects in Python now hold both a ``__javaarray__`` and a ``__javavalue__``. This eliminates need for special paths for arrays. * ``_getClassFor`` is now overloaded to work with array classes. Thus asking for a ``JClass('[java.lang.Object;')`` will now correctly return a JavaArrayClass. * Constructing a string now shortcuts to avoid methodoverload resolution on new instance if given a Python string. * Reworked the GIL handling. The previous model was doing all the release locks on the JPJni calls automatically for almost all jni transactions. This would be fine, except that many utility functions were using those same calls regardless of whether is was a good time to release the lock. This ultra fine grain locking was effectively allowing any call to JPJni methods to become a break point, including those calls in critical sections such as ensureTypeCache and TypeManager::findClass. Any time it loaded a class or looked up a name it could be interrupted and thus end up in a corrupt state. Thus I moved all of the GIL calls to those places where we call user code on the type returns and the object constructors. Thus cuts the number of GIL transactions greatly and eliminates the need to deal with trampling global resources. The refactor exposed this a bit more because the removal of TypeName meant that we did a lot more transactions to get the class name. But that does not mean the flaw was not there before. If our tests cases had been any more aggressive about creating class instances during execution it would have overrun the TypeManager table and all would have failed. * Removed the previous default option to automatically convert ``java.lang.String`` to either a Python string or a unicode when returning from Java. This does mean some string operations now require calling the Java string method rather than the Python one. Having strings not convert but rather remain on the jvm until needed cuts the conversion costs when working with Java heavy code. I added a caching mech so that if we need to convert the string multiple times, we don't pay additional over the previous option. * A special ``toString`` method was added to ``PyJPValue`` to convert Java strings to Python strings. This can convert Java string resources to Python ones on request. Proxy changes ~~~~~~~~~~~~~ * Proxy as implemented previously held only a pointer to the proxy object and from this proxy object it lookup up the callable using either a dictionary or an instance. The majority of the resources were held by the ``jpype.Proxy``. This was replaced with a more general function in which the ``PyJPProxy`` proxy holds two resources. One is an object instance and the other is a lookup function that turns the name to a function definition. This supports the same use cases but eliminates the need for finding resources by convention. There is no need for the proxy in Python to have any specific layout other than holding a PyJPProxy as ``__javaproxy__``. Thus allowing alternive structures such as Proxy by inheritance to work. * Memory handling was changes slightly as a result so that the reference queue is now responsible for cleaning up the proxy. Proxy handle instances are generated whenever the proxy is passed to Java. Thus we form no counting loops as the proxy has no reference to the handles and the handles hold a reference to the proxy. Exception changes ~~~~~~~~~~~~~~~~~ * Changed all exception paths to use ``JPypeException`` exclusively. The prior system did way to much in the Exception constructors and would themselves crash if anything unusual happened making changing of the system nearly prohibitive to debug. Everything bubbles down to ``toJava`` and ``toPython`` where we perform all the logging and pass the exception off. This also centralizes all the handling to one place. * This pulls all the logic from ``JPProxy`` so that we can now reuse that when returning to any Java jni native implemented function. * Same thing for Python, but that was already centralized on ``rethrow``. * Reworked exception macros to include more info and introduced ``JPStackInfo``. It may be possible to connect all the stack info into the Python traceback (via a proxy class) to present a more unified error reporting. But this work is currently incomplete without a Python layer support class. * Integrated ``JPStackInfo`` into tracer to give more complete logs when debugging. Code quality ~~~~~~~~~~~~ * Applied a source formatter in netbeans. It is not perfect as it tends to add some extra spaces, but it does make faster work of the refactor. Custom spacing rules were applied to netbeans to try to minimize the total changes in the source. * Improved error handling where possible. * Rework ``JPTracer`` so that reporting from places that do not have a formal frame or could not properly throw (such as destructors) and still appear in the trace log. All ``TRACE`` macros were moved to ``JP_`` so that were less likely to hit conflicts. Removed guards that complete disabled Tracer from compiling when ``TRACE`` was not enabled so that unconditional logging for serious failure such as suppressed exceptions in destructors can report. * Defensively added ``TRACE`` statements whenever entering the module for a nontrivial action so that errors could be located more quickly. * Removed ``MTRACE`` layer as Java local frame handles all cleaning tasks for that now. * Replaced TRACE1, TRACE2, TRACE3 with a variodic argument macro ``JP_TRACE`` because I am too lazy to remember to count. * Renamed functions to best match the documented corresponding function in the language it was taken from. Thus making it easier to find the needed documentation. (Ie ``JPyString::isString()`` becomes ``JPPyString::check()`` if the corresponding language concept is ``PyString_Check()``). This does mean that naming is mixed for the Java/Python layers but it is better to be able to get the documentation than be a naming idealist. * Used javadoc comments on header of base clases. These strings are picked up by netbeans for document critical usage. * Moved method implementations and destructors out of headers except in the case of a truly trivial accessor. This has a small performance loss because of removal of inline option. This reduces the number of redundant implementation copies at link time and ensures the virtual destructor is fixed in a specific object. We can push those back to the header if there is a compelling need. ``jpype`` module changes --------------------------- Because these do affect the end user, we have marked them as enhance, change, remove, bug fix, or internal. General ~~~~~~~ * **(enhance)** ``__all__`` added to all modules so that we have a well defined export rather that leaking symbols everywhere. Eliminated stray imports in the jpype namespace. * **(enhance)** Add ``@deprecated`` to ``_core`` and marked all functions that are no longer used appropraitely. Use ``-Wd`` to see deprecated function warnings. * **(enhance)** Exposed ``JavaInterface``, ``JavaObject``, ``JavaClass`` so that they can be used in ``issubclass`` and ``isinstance`` statement. ``JavaClass.__new__`` method was pushed to factory to make it safe for external use. * **(enhance)** mro for Java Classes removes ``JavaInterface`` so that ``issubclass(cls, JavaInterface)`` is only true if the class not derived from ``JavaObject``. * **(enhance)** All classes derived from ``java.lang.Throwable`` are now usable as thrown exceptions. No requirement to access special inner classes with exception types. Exceptions can be raised directly from within a Python context to be passed to Java when in proxy. Throwables now use a standard customizer to set their base class to the Python Exception tree. Deprecated ``JException`` * **(enhance)** ``args`` is a property of ``java.lang.Throwable`` containing the message and the cause if specified. * **(enhance)** ``JChar`` array now converts to a string and compares with string properly. Conversion uses range so that it does not try to convert character by character. * **(remove)** ``JByte`` array is not a string type. It is not a string in Java and should not be treated as a string without explicit conversion. Conversion path was horribly inefficient converting each byte as a Python object. Test marked as skip. * **(change)** Array conversion errors produce ``TypeError`` rather than ``RunTimeError``. * **(enhance)** ``JArray`` now supports using raw Python types as the specifier for array types. It will convert to the most appropraite type or return an error. * **(remove)** property conversion customizer is deactivated by default. This one proved very problematic. It overrided certain customizers, hid intentionally exposed fields, bloated the dictionary tables, and interferred with the unwrapping of exception types. We can try to make it an optional system with ``import jpype.properties`` or some such but it will still have all those problems. Best to kill this misfeature now. * **(enhance)** ``JArray`` classes now have ``class_``. We can access the component type. This makes them more consistent with ``JClass``. (required for testing) * **(enhance)** Use of constructor call pattern eliminated the need for use of a separate factory and type. Thus we are back to the original design in which we only need to expose a small number of "types". This was applied to ``JArray``, ``JClass``, ``JException``, and ``JObject``. Use of ``isinstance()`` and ``issubclass`` now supported. The only challenge was keeping box types working. * **(remove)** Functions that return a string now return a ``java.lang.String`` rather than converting to Python. Thus when chaining elements together in Java will get the full benefit matching types. The previous auto convert has been removed. * **(enhance)** ``java.lang.String`` now has much more complete set of Python operations. String conversions are now cached, so the penalty of converting is kept to a minimum. Wrappers ~~~~~~~~~ * **(internal)** Rewrote the ``JWrapper`` module from scratch to reflect the use i of ``JPValue``. Renamed ``_jwrapper`` to ``_jtypes``. The concept of wrappers has now been lost internally. All objects and primitives are just values. * **(enhance)** Created import module containing all of the symbols needed for creating types in jpype so that we can support a limited import statement ``from jpype.types import *`` * **(enhance)** ``JString`` contructor now returns a ``java.lang.String`` object. Removed ``JStringWrapper`` as ``java.lang.String`` serves its purpose. * **(enhance)** ``JObject`` now returns an object with the Java type as a functional object rather than a dead end wrapper. This does allow some redundant things such as converting a Python class wrapper into a class ``JObject(java.lang.String) == java.lang.String.class_`` but otherwise seems good. * **(enhance)** 'JObject' and 'JString' accept 0 arguments to generate a generic object and empty string. * Tried to be more consistent about returning errors that are valid in Python. - Too many or two few arguments to a function will throw a ``TypeError`` - Value conversion out of range will throw ``OverFlowError`` - Value conversions that are the right type but invalid value will give ``ValueError`` (char from string too long) - Type conversions that cannot be completed should give ``TypeError``. - Errors setting attributes should give ``AttributeError`` such as trying to set a final field or trying to get an instance field from a static object. - Arrays access should produce ``IndexError`` on bad range. (it would be nice if these also mapped to Java errors and the corresponding errors in Java were derived from the Python error so that we can properly look for ArrayIndexOutOfBoundsException (derived from IndexException). But that is too heavy to attempt now.) * **(enhance)** ``JArray``, ``JException`` and ``JObject`` report as JavaClass when using issubclass. * **(enhance)** Short cut for just adding a base class as a customizer. Internal ~~~~~~~~~ * **(internal)** Changes corresponding to the ``__init__`` rework to match revised ``PyJP*`` classes. * **(internal)** Changes corresponding to the capsule removal. * **(internal)** Remove ``SPECIAL_CONSTRUCTOR_KEY`` as everything that uses it can recognize a PyJPValue as indicating they are receiving an existing Java resource as input. All special handling required to construct objects from within C++ layer were thus eliminated. * **(internal)** Removed almost all required resources from Python needing to be register in ``_jpype`` with the exception of getClassMethod. * **(internal)** Java class customizers did not need to be deferred until after the JVM is initialized. Pushing them into the dictionary immediately fixes issues in which a customizer was not applied to classes during early bootstrapping. This eliminates a large number of the need for calling initialize on each jpype module in ``_core``. * **(internal)** ``JArrayClass`` and ``JClass`` are the same for purposes of Customizers and class tree. * **(internal)** Customizer code and dictionary moved to ``_jcustomizer`` so that i it can be shared between Object and Array classes. * **(internal)** Converted ``JavaClass`` to more Python like "try first, eat an exception if it fails" philosophy to increase robustness to failure. This eliminates the problems when a new base class is introduced with a customizer without setting up a meta class. * **internal/enhance** Broke connections between boxed types and wrappers. User supplied wrappers can implements specified "Value" method. Wrapper types now have similar methods to boxed types with appropriate range checks. * **(internal)** All ``$Static`` meta classes have been eliminated. There is now only one tree of classes. A single meta class ``JClass`` serves as the type for all classes. Bugs ~~~~~~~ * **(bug fix)** Fixed bug in ``jpype.imports`` in which it would not install its hooks if loaded afer the jvm was started. * **(bug fix)** Fixed bug in JBoxed type wrappers in Python which would lead ``java.lang.Double`` and ``java.lang.Float`` to have an integer value when boxed was corrected. * **(bug fix)** Fixed bug in ``JObject`` that was preventing classes from being wrapped as objects. Verified a number of test cases in the test suite. * **(bug fix)** Reenabled the throw from Java test during proxy. The issue was that jpype was releasing resources before it could transfer control a ``PyErr_Clear`` removed the reference and thus our throwable was invalid. It was dastardly to find, but the fix was moving a statement one line up. Documentation changes ~~~~~~~~~~~~~~~~~~~~~~ * Documentation of major class methods have been added as well as marker whereever the underlying assumptions are not reasonably transparent. * Action items for further work have been marked as FIXME for now. Incomplete ---------- These tasks had to be pushed over post 0.7 release. * Finish specialization of ``JPArray`` classes for ``byte[]`` and ``char[]`` * Deal with fast array conversions misuse of types. ``int[]<=>float[]`` * Direct bridge methods for ``char[]`` are currently bypassing the unicode translation layer. It is unclear what Java does with extended unicode when dealing with ``char[]``. * Add a system to register a translation customizer so that we do not need to modify C++ code to add new simple translations like Python date to Java Instant. These would be installed into the PyJPClass during class wrapper customization. We will need to make sure each class has a Python type wrapper cached in ensureTypeCache so we are guaranteed to find the conversion. * Add tests for Exception.args jpype-1.3.0/doc/Makefile000066400000000000000000000151461405671516700150720ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/JPype.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/JPype.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/JPype" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/JPype" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." latexpdfja: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." xml: $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." jpype-1.3.0/doc/_static/000077500000000000000000000000001405671516700150515ustar00rootroot00000000000000jpype-1.3.0/doc/_static/theme_overrides.css000066400000000000000000000002411405671516700207440ustar00rootroot00000000000000/* override table width restrictions */ @media screen and (min-width: 767px) { .wy-table-responsive table td { white-space: normal !important; } } jpype-1.3.0/doc/android.rst000066400000000000000000000064351405671516700156050ustar00rootroot00000000000000JPype for Android ================= We ported JPype to the Android system. There are a number of important differences between JPype on Android and on a JVM. The Andoid platform uses the Dalvik virtual machine(DVM) which supports only a portion of the Java specification. As a result some portions of JPype have been removed or function differently. Supported Functions ------------------- The following features operate the same on both the JVM and DVM version. - Java classes using ``jpype.JClass`` - Access to Java methods and fields - Java arrays using ``jpype.JArray`` including slicing and direct transfers - Java primitive types, string type, and boxed types - Java.nio byte buffer including memory mapped data - Python collections API for Java collection types - Class customizers and type conversions - Support of scientific codes such as numpy - Implementation of Java interfaces using JProxy Functional differences ---------------------- When using JPype on Android, the virtual machine is started prior to the start of Python. Thus, there is no need to lauch the machine. Instead to use jpype only the statement ``import jpype`` is required. In addtion, the following functions have been removed... - ``jpype.startJVM`` is removed as the virtual machine cannot be started more than once. - ``jpype.shutdownJVM`` is removed as DVM cannot to stopped during operation. - ``jpype.addClassPath`` is removed as DVM does not support class path based jar loading. Dex files can be loaded dynamically using the Android API. - ``jpype.getDefaultJVMPath`` is removed as there is no JVM on Android. - ``jpype.beans`` has been removed as adding addition properties for semantic sugar increase the memory profile unnecessarily. - attach and detaching of threads is not allowed and those entry points have been removed. Removed JPype Services ---------------------- Not all JPype services are provided on Android as some functions depend on the internals of the JVM. These include... - The dynamic class loader does not operate on JPype as DVM does not support jar files. - jpype.imports and jpype.JPackage use the jar file system to identify packages which is not available on DVM. Therefore, all classes must be loaded use ``jpype.JClass``. - jpype support for Javadoc was removed as DVM does not support Javadoc jars in the classpath. - jpype does not install interrupt handlers for ^C on Android. Unsupported Java libraries -------------------------- Some Java libraries are not supported on Android. - Bytecode manipulation libraries to not function on DVM. This means generation of dynamic classes, manipulation of loaded classes, and Java agent code will not function. - Some standard Java libraries are not implemented on Android such as AWT. Jar libraries that access these unimplemented libraries will not function. - Private JVM internal classes such as ``sun.*`` are not implemented and cannot be used. Behavior differences -------------------- Some changes in JPype behavior occur simply because the DVM operates differently. These changes include - java.lang.Class.forName will not load classes from classes.dex. Attempting to access classes with forName will get ClassNotFoundException. Applying forName to base classes that use the system classloader function as expected. jpype-1.3.0/doc/api.rst000066400000000000000000000061071405671516700147320ustar00rootroot00000000000000API Reference ============= JVM Functions ~~~~~~~~~~~~~ These functions control and start the JVM. .. autofunction:: jpype.startJVM .. autofunction:: jpype.shutdownJVM .. autofunction:: jpype.getDefaultJVMPath .. autofunction:: jpype.getClassPath .. autodecorator:: jpype.onJVMStart Class importing ~~~~~~~~~~~~~~~ JPype supports several styles of importing. The newer integrated style is provided by the imports_ module. The older ``JPackage`` method is available for accessing package trees with less error checking. Direct loading of Java classes can be made with JClass_. For convenience, the JPype module predefines the following ``JPackage`` instances for ``java`` and ``javax``. .. autoclass:: jpype.JPackage Class Factories ~~~~~~~~~~~~~~~ .. _JClass: .. autoclass:: jpype.JClass .. autoclass:: jpype.JArray .. autoclass:: jpype.JException Java Types ~~~~~~~~~~ JPype has types for each of the Java primitives: ``JBoolean``, ``JByte``, ``JShort``, ``JInt``, ``JLong``, ``JFloat`` and ``JDouble``. There is one class for working with Java objects, ``JObject``. This serves to cast to a specific object type. .. autoclass:: jpype.JObject .. _threading: Threading ~~~~~~~~~ .. autofunction:: jpype.synchronized .. autoclass:: java.lang.Thread :members: Decorators ~~~~~~~~~~~ JPype uses ordinary Python classes to implement functionality in Java. Adding these decorators to a Python class will mark them for use by JPype to interact with Java classes. .. autodecorator:: jpype.JConversion .. autodecorator:: jpype.JImplementationFor .. autodecorator:: jpype.JImplements .. autodecorator:: jpype.JOverride Proxies ~~~~~~~ JPype can implement Java interfaces either by using decorators or by manually creating a JProxy. Java only support proxying interfaces, thus we cannot extend an existing Java class. .. autoclass:: jpype.JProxy Customized Classes ~~~~~~~~~~~~~~~~~~ JPype provides standard customizers for Java interfaces so that Java objects have syntax matching the corresponding Python objects. The customizers are automatically bound to the class on creation without user intervention. We are documentating the functions that each customizer adds here. Information about Java methods can be found in the Javadoc. These internal classes can be used as example of how to implement your own customizers for Java classes. .. autoclass:: java.util.Iterable :members: :special-members: .. autoclass:: java.util.Collection :members: :special-members: .. autoclass:: java.util.List :members: :special-members: .. autoclass:: java.util.Map :members: :special-members: .. autoclass:: java.util.Set .. autoclass:: java.util.Iterator .. autoclass:: java.util.Enumeration .. autoclass:: java.lang.AutoCloseable Modules ~~~~~~~ Optional JPype behavior is stored in modules. These optional modules can be imported to add additional functionality. .. _imports: .. automodule:: jpype.imports .. automodule:: jpype.pickle .. autoclass:: jpype.pickle.JPickler .. autoclass:: jpype.pickle.JUnpickler .. automodule:: jpype.beans .. automodule:: jpype.types jpype-1.3.0/doc/attach_debugger.png000077500000000000000000000412531405671516700172510ustar00rootroot00000000000000PNG  IHDREC4zAsRGBgAMA a pHYsttfxB@IDATx^|e_@J^Q "4+ XQ8EzNِ)`SDDQ&Ed&,!n* _3ݝ7{fcBwv!7ObbbܭPB^A ١\PBGv ') B#"VDRxС(ٳ'}[®]`nY\\[|ɒ[[|`*(֭.[HeʗbEP.۴+]ɝQ6֪}c;0#edhP )^&eӴѺ1;l ~g+'m3V%sء]m8d11(RZ[`E1 Uun$yD/PUkn* މJ}NTBvvO@E>[z"2©EFsիWKRן@l[nS$駝h?_jgdb٦ElíD>{[=VlhN? e~٘n:YÚ-Kܱ~C1fZJXk_|ت׮nvVmNV&!CI 64r^  :1vȶ_f*WJX5wX)[^=V?Z>ʕ8Ѫ5Wqsk[Aӷxwkqf[k-'[y[Ot/ x-ZUzx o_]{|wR|rСN x^}UW[?|)if@7߸΋.{kyvTNQNnRΤ{= > 9ܹ͚5-馛gqӁo=Nqӧ]|E'%f[lݻU^ +J_J.Ǝϙkv饗sf6mre˖Mc=fӟm[^\ҷo_W%=sֻwo. ?CٸqlڵE*Zn{@裏O){i<:Q7%npgǪL.uZjYV-]E8U>07o6xw9s9_JOzsڟcC;6U &nWk.6lX8cW/h֯J*%Bm۶={FoԨQ=:k ^*qٳ J{wpGի_|aڵs+Vtוl߾V\ϙ]uU^o 믿6-{ǭf͚dɒ~I] N:-]u%wyԥot]-> mTӿ@<%Q}el}yɒ%vA73ҥ˸$>q-IƌKՂpYgY~$ݝ;wiQ,}짟n@MR*t%u ԃXR.V&M,.6oɟgz2m47JZQu%eDR~/o.`4Pyu)(UU֭ZHlZ* Oӣ]-Dz]'Hl[ʕCCjQ׏S믿޵^A-k_|[qؿkٻ䒤mƌ7BFyT7^ hԍZwzl RyF-5l2wJ/ BSu]ZtSZ»> ҵ y-nW!_w1[L駟&Z MW۶m%֪RTN RTm; ̓Aůnuk0drˌ~V8"? T:>]J_}.ZjXb^p^;C'Ry4ۖŊd% އHke)Z Z-L-ڀG:ɝ8q=n^얥?yW_A(G̨b҅~RhUKlٮP#r/#ػ*?uʣٶ*OX. (P79^S^\H4KI,X~R'anb(ʹmE+|z/.&S%Ot9e)Fe~KWF*mwVЅ>D#9rK44(0 tdD3dW?@Q/r3+AQFRR%~m!)*U6nJ+[ RS2j$JQKMZm[NPW^Z%Rv-TH`P@K&_~ *D*zԢش}Qy LtTffxP4bGyF-*]cHT1-Ms5<^ODdZwSX R9QrI;Y2(R0ūNzcT]VQ.xTgV %UCכ NT*Ful%2(hNHpPRrS$4|0kFϥ_w @4&Ol;wvilTPs>̆js=GrLf /w^-\^z%YvZʟ;[n^~ea=. Q9^5hѼ'gcѢEv5u쪫X4h|~i={ؕW^i{e˖֣GwGA#ݧg4AѶmK/on$TÆ mn#͛篕7_֬YK. >wm@v,}]@իW!Oqi=Wnx믿k_^R{6sҤI$onjԨ˔)cƍsӁo w)ifGo\~Ewy-nq[᝱L6~a馛'3gZ۳ʛԪ5b(ZWvjt׫W/XU\ٮz۾}_TYzɒ%iӦ~ɑvoyٖ-[{E)S 'Ow-?::CVd ǥ\j9Lj\g͚K4IkuYG<6{z_D]:2=V'=Qw]wϏ@u 7`>w-̩Ih u"moJi;2}]r%o/_-B_|; 褫gϞ\[6 >ܵ0yGC8#?slE{[|NwC^%jyp[ti誫 +W.TBP=cr=䓡x TjПɓ._B]taTRꆼpr_PJBŊ vinC=c GVVrU믿ꠌ{lC_īlC;v -\ݼ_[n~i(ԩSPڵC&L%&&~g$:sB-㼃_DC;w ˡƍvrW{r燼3G7ݢEw`wӒz?4w\725ӯ_Ђ B_~y.K_S/y5H6mw\VX;-?>3nP2eB ygt;Ie駟|J_훼 NM)YyXt ü+374Qt\3fLZaÆe֭swu p>rS;e((4iN>=/tvB~iZ_Рm۶.B p.V\/cÆ (Yfmܸ14sL|͚5nt֗{Æ ny4۪}h֭'&E*y@eڿ˖-s>_z$Gy\p cǏgvoj_͏92TpЦMܼԖDByM G|ܑTY }wk׮+Ww}\}?\޳;7n+{\嘖o^rHۛR4맶YyX_ӣ`Ea}+ܴ(({&MeC '4e>Sjr eLWR#fZzuSՍ$来fΝ؏?KU}\].][]Rw\ %6h=NU.Օ\2m ݨ:uXB\r5k_5mzkzLHHpLZh%VxQwu ;xAc bygU.)-ʿ)U˟;\F>J?4k̼nr^O4I>+ KMzEkh;:>_=;0"5Š+rS?D zNMZ7}F#)etp}J*TN8߿1cصzp^I{1)ELm ทRZ˳"CAe>5AYx~0uS悗/. QZ TTkժyg[e[F۪>ڗ_nsQ }ժUݧs_ne6cƌ[۶mt@_Tw6jfT{iȰG9p? NѼhU\!$IO/ddu\*d在RTUW]喧&>ш)ethdRn\vr1%}u >>S:]fM p.]O?%Ѽg Ekv[o/9Z@,^݋Z'$;O>kAٳ}$9y^ZtUR:+YZҚ5ofFtLU:t`_~ VjS #zlǎ]_p kRn=3p GA>S.4)(Xd $$2U̢נkkZCH~x ޗӧ3wJPeztiZoU*KԤ\'lGH+ZmZzaEK'J$}3@7|=n^얡Hzȝ)\]֗I&Ƹq{fΝZg*jժX)Aː_*Ks2mSTP7|7-+V .Pѭ[7+[ի_ύPS~+7rwƪ3SD|MEtps`o>0O=ރ[-V; te7xYƝjȑ#܈% SKާ2R[/uI]+6ѾhhDՋ/5tbB'=mPkmjlذar%R7vuIZ7/}FSrh7\4G)2B[rLI33ϸV cz4R'WW7g"ݔ0En$T蔈r{Kh@.ndN0+父|šN;4%z.\2|0IeAtFU7%(*1|Yn݂C7n)I6i߼^yz4&<9Fh2*ǥ\޽e5wB#2Xޗ߽EMH"mwjz)=F?i{S~4ۑRz+7j FUN@(ݧ%1㢣LPZXկo1psn%Zؙw`qgթo5z 9E]a9#{=+9Z:n%]tƯVشU5YY PE5Ey,(n꺞YE.=9]$@xYJƱ=n`tBՉCKQ>7kwBFA)*wYxq7RJV">>hSz>(h4h"E <x<E"ACP!(x<E~,ٸq?Sre*zE޽{jժHXb\>x#X(D- PNowvWX9drtMcIо}{w0`+9Eͳ~^y{Ǔu۷off.ZvZʟ˟?2=cϻ۹kjJ׭t=c#F{O5l)۷kE]дk.9rVNNZ_Æ ƍ[׮](5k{K[lKzYO>KͶmQY n;{)iӦٸqe˖6qDn:غu]z%VlYkڴ}~m/W_G}䗤o]:zyf~^zYŊuz۾}_TN:J,'5;u;sg=Slʔ)nyf^YAѺu駟vɓDVJ:d-\*V`/Uɿ{^[ɞ{Yv+\ST)$jI8?:gt{ 6؄ \oW&)o֭[JZCnvYnt^q$ڜ9s?ŋ%fwqmzi3f̰.]%i{ .tAW_}uD_=\F-Wk/5mԩ6j( )LI]]z5jȮJmT`;ݶKf^Y#.BWePBvEV8k}CXK(x']KA]%fEI&5k\$ꪫ\*[%C-MEQާOҠ"?U oZ9E˻iQZ8 <KC5\ {!%UиؤבN8>Sj֬WxQÆ MZW>U0zgjI*^RK~\VZق ܕ3Ȋ R^Z[hΝ\믿nv_nݺJ5|ýYf\Г$ QCr\P [»rL2scMMz_:CuyʕE^isOg}fcǎxɁCoVmڴK -[}T]]~Tѿ/Z'6{l_~ 6>s֥Kܹs;vt]Aў={"ǃ"tvQՅhKE +VpnSE{駻YQ?ڱt2㢛r ?65J VRr<,6x 7W<M]7p~ w7ښIyX ƛntyT ^+T(|111֛oj*uH̛oE-(i{5ޜzj#4c7<&Ie51+M V ^Z-=`'_사o6nJ+.\k5CCs`WVˎZ*U/9{lĈ_מycAѶm۬o߾V^=kРvmcl֬YveYZqƶegiӦٸqe˖6qD|ذaֿ7 ^z /`=UZ՚hnƬW5j&LeB7D'Ov-RH4i]ƪWnny%\E_hQ+_oM#G5ktAc||k)RygsiyѢqVX1PƹeLEjQu-Z1iӦ^lv!k֬ 0rDONPBV\9q=NU\/^ˢE}PVZ5?~ɦ1cƸBEuԱ&M^`;wt:j-̙3vf6Vf j5,Y!֭mLx#ArFmK-stS.ѨQ,ׯv(U(_ \s5ZE6uTLC䦑q7xY\.p| /\ppjE~7nh+VtAWlVR#q+J~ٲeS DPzD@tM#"F!(xNܹs)38ßA3ACP!(x<E"Ao# ,as˗/͛s 5g϶ڵksѣ CP!(d8O>[ZLL.]N?tQ_2h6k,:uNP(Zjn^M6mlȐ!n^?_xVzPBY.X9fd7Xַo_Avmَ;\W^jժe?\+Ƹqe˖6qDްaìniIٲe]Z@;֬ZesqY- RP~:u{m6lpi}뮹[\h^- իWɓ'֭[[]Rzj֭F)PQwW_/1XG (իWd*(UV֢E ;kժU.ϨO>V~}wS@gڵ#.B;N:VdIQhQ+_|rˇZڷo撚5 \=j(PKr^|E8-ZZ@~Is,>>>@ׁ`:rr/'|z/MÇ_m~zny͚5}Vo2ժU哄'ŋݽ(hܧnLuG4%[Ϻm 5K^@~D뀺Ú4ibog sN;vk-Nϟ%YbEr62;r˹hL-<=q_?emv3fw}ԅrl 4 {Ѷt2kԨ)H,e\s5ZE7v!#F4RgwLvIݺu]s)S?Y*UoJ zb[sαF Z=Ҭȯk$]TT)IdjP%5nҖݿ.6 cccec!)ʑ9#"G"gܹs)gFx>x<E"ACP!(x~8|rk޼?R3{l]?=<E8`wyuyOr}۽{?w+¾kT5i_\|Ů/}6n8i 6^z%KHH-[K3""˕y?n=۷yoG-ׯ5ksi{5 {Ǿ+5}C٬Y?}={tO"ںuZjYV-m~W5hn6۱c_j֣G7|򗿸gyƦMZZli'Nt#+P7n8H]jAѺu\O?mgYѢE+ɓ'[oeڵ!CkJ.cϷ>/I*۰aM0>#ܷr_jj*۹s?g.`Zz[]O>7?ֵkW[b?JKv͟R>SԽkիW3}XMk׺ǧD炚˻hERH4i]ƭ`*-jRB78r%(R(T)]KLL y睮UV.&hiڴ`:()n >:r `~ r%('~Oo\+[x"IP&P /TVƏo~_3f_<)9Yy6>lrў={ܵ}ԩ}hh^CcǎuE 빌s(zĈny@UI3gt~a_Kd!5Aw}ꫯڲeuG93~x{{7|$4|.oa ,rG^=c׿Նjm/ٱWrfРA{s|sy[vcڵ}vܹߊ+fʕs{6mlڵZIĉ9!Cfܑ͚o[okܸmܸ~aql+;A P믿?>o]Y~}J&LzY||Q˚Z3ΝD=3?[ 6"[lݻ1rM2/9Z^矷*Vhs?8_+v[O&]+>,Y/MxbkwޱڵkK 9F*T^> oWܬYϩʟx ^uYG%ꦛnr (Y5m/X"( ;o`o)ʖ-kW;hZG;h k׮p v! t_rX׮]ݽZ= ."rK _~ݷjݧE͋/h֯J*>ܼy}Vre{'RڦNjFrҸq}%"Ƞ-؜9s[|M<.wa9UDJUFZtN;ȨBO- Sk%-%H̜9Ӗ4 `(0I_nM48k۶QAjԵ?<3.L-FQñBPnÇq j*w?dBK.uS~%^%#$n疠뫯r 6LZ2T҂)H0_rOZnm͚5s-)ׯO%}f39p>+E & 3f$t ՕSJÔhir;<[bW)S^uєwAdF|jY>&"fuԱ;V,Y?+!MFu=zhWudH". >&Uď>V^z%k޼;RKA08SE9 ֭Zޔߦd46~=?3߇crرc]˅-T)~N:]8qq.עZj6l0{wd>[GVV-zk<#vkNw_S *M>}EF5zL 'l#Fե}7u*T%PGCy-ZpK ߗ\ñï8,\ +a&F}6`[~U߸RTz_;AK~4/ʫZܵk5l_rZhEGPFkV{lj?\!c_Rฒ*G],0#@ND]XkCɫ}"QkO e$ YZCFd>"(p\ш%*']w]vrMHȏ:7sOvk"ɜ.Ԙ[?}]?uunb_E+JD7")B~Qv`_}{{_h ย۴iy7()By!JU>G :;2TGc_瞜EK:ؿih EdKHܓCNCP!(x<E"ACP!(*Z:IENDB`jpype-1.3.0/doc/caller_sensitive.rst000066400000000000000000000101331405671516700175060ustar00rootroot00000000000000:orphan: Caller Sensitive Methods ======================== The following methods use the caller sensitive (as of JDK 12): - ``java.io.ObjectStreamClass.forClass`` - ``java.io.ObjectStreamField.getType`` - ``java.lang.Class.forName`` - ``java.lang.Class.newInstance`` - ``java.lang.Class.getClassLoader`` - ``java.lang.Class.getEnclosingMethod`` - ``java.lang.Class.getEnclosingConstructor`` - ``java.lang.Class.getDeclaringClass`` - ``java.lang.Class.getEnclosingClass`` - ``java.lang.Class.getClasses`` - ``java.lang.Class.getFields`` - ``java.lang.Class.getMethods`` - ``java.lang.Class.getConstructor`` - ``java.lang.Class.getConstructors`` - ``java.lang.Class.getField`` - ``java.lang.Class.getMethod`` - ``java.lang.Class.getDeclaredClasses`` - ``java.lang.Class.getDeclaredField`` - ``java.lang.Class.getDeclaredFields`` - ``java.lang.Class.getDeclaredMethod`` - ``java.lang.Class.getDeclaredMethods`` - ``java.lang.Class.getDeclaredConstructor`` - ``java.lang.Class.getDeclaredConstructors`` - ``java.lang.Class.getResource`` - ``java.lang.Class.getResourceAsStream`` - ``java.lang.Class.getNestHost`` - ``java.lang.Class.getNestMembers`` - ``java.lang.ClassLoader.getParent`` - ``java.lang.ClassLoader.getPlatformClassLoader`` - ``java.lang.invoke,MethodHandleProxies.asInterfaceInstance`` - ``java.lang.invoke.MethodHandles.lookup`` - ``java.lang.Module.addReads`` - ``java.lang.Module.addExports`` - ``java.lang.Module.addOpens`` - ``java.lang.Module.addUses`` - ``java.lang.Module.getResourceAsStream`` - ``java.lang.Package.getPackage`` - ``java.lang.Package.getPackages`` - ``java.lang.reflect.AccessibleObject.setAccessible`` - ``java.lang.reflect.AccessibleObject.setAccessible`` - ``java.lang.reflect.AccessibleObject.trySetAccessible`` - ``java.lang.reflect.AccessibleObject.canAccess`` - ``java.lang.reflect.Constructor.setAccessible`` - ``java.lang.reflect.Constructor.newInstance`` - ``java.lang.reflect.Field.setAccessible`` - ``java.lang.reflect.Field.get`` - ``java.lang.reflect.Field.getBoolean`` - ``java.lang.reflect.Field.getByte`` - ``java.lang.reflect.Field.getChar`` - ``java.lang.reflect.Field.getShort`` - ``java.lang.reflect.Field.getInt`` - ``java.lang.reflect.Field.getLong`` - ``java.lang.reflect.Field.getFloat`` - ``java.lang.reflect.Field.getDouble`` - ``java.lang.reflect.Field.set`` - ``java.lang.reflect.Field.setBoolean`` - ``java.lang.reflect.Field.setByte`` - ``java.lang.reflect.Field.setChar`` - ``java.lang.reflect.Field.setShort`` - ``java.lang.reflect.Field.setInt`` - ``java.lang.reflect.Field.setLong`` - ``java.lang.reflect.Field.setFloat`` - ``java.lang.reflect.Field.setDouble`` - ``java.lang.reflect.Method.setAccessible`` - ``java.lang.reflect.Method.invoke`` - ``java.lang.reflect.Proxy.getProxyClass`` - ``java.lang.reflect.Proxy.newProxyInstance`` - ``java.lang.reflect.Proxy.getInvocationHandler`` - ``java.lang.Runtime.load`` - ``java.lang.Runtime.loadLibrary`` - ``java.lang.StackWalker.walk`` - ``java.lang.StackWalker.forEach`` - ``java.lang.StackWalker.getCallerClass`` - ``java.lang.System.getLogger`` - ``java.lang.System.getLogger`` - ``java.lang.System.load`` - ``java.lang.System.loadLibrary`` - ``java.lang.Thread.getContextClassLoader`` - ``java.security.AccessController.doPrivileged`` - ``java.security.AccessController.doPrivilegedWithCombiner`` - ``java.util.concurrent.atomic.AtomicIntegerFieldUpdater.newUpdater`` - ``java.util.concurrent.atomic.AtomicLongFieldUpdater.newUpdater`` - ``java.util.concurrent.atomic.AtomicReferenceFieldUpdater.newUpdater`` - ``java.util.ResourceBundle.getBundle`` - ``java.util.ResourceBundle.clearCache`` - ``java.util.ServiceLoader.load`` - ``java.util.ServiceLoader.loadInstalled`` - ``java.util.logging.Logger.getLogger`` - ``java.util.logging.Logger.getLogger`` - ``java.util.logging.Logger.getAnonymousLogger`` - ``java.sql.DriverManager.getConnection`` - ``java.sql.DriverManager.getDriver`` - ``java.sql.DriverManager.deregisterDriver`` - ``java.sql.DriverManager.getDrivers`` jpype-1.3.0/doc/conf.py000066400000000000000000000262171405671516700147320ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # JPype documentation build configuration file, created by # sphinx-quickstart on Wed Feb 26 20:16:40 2014. # # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. from unittest import mock import sys import os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.insert(0, os.path.abspath('..')) sys.path.insert(0, os.path.abspath('.')) # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = ['sphinx.ext.napoleon', 'sphinx.ext.autodoc', 'sphinx.ext.autosectionlabel', 'readthedocs_ext.readthedocs', ] autosectionlabel_prefix_document = True # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'JPype' copyright = u'2014-18, Steve Menard, Luis Nell and others' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. class ObjectMock(object): def __init__(self, *args, **kwargs): self._kwargs = kwargs self._to = mock.Mock object.__init__(self) def __getattr__(self, key): kwargs = self._kwargs m = self._to(**kwargs) object.__setattr__(self, key, m) return m class TypeMock(type): def __new__(cls, name, bases=None, members={}, to=mock.Mock, **kwargs): if not bases: bases = tuple([]) members['__init__'] = ObjectMock.__init__ members['__getattr__'] = ObjectMock.__getattr__ members['_kwargs'] = kwargs members['_to'] = to members['__slots__'] = [] return type.__new__(cls, name, bases, members) def __init__(self, *args, **kwargs): return type.__init__(self, *args) def __getattr__(self, key): kwargs = self._kwargs m = self._to(**kwargs) type.__setattr__(self, key, m) return m class _JClass(type): pass class _JClassHints(object): def __init__(self): self.bases = [] def _addClassBases(self, *args): pass def _addTypeConversion(self, *args): pass def _addAttributeConversion(self, *args): pass def _excludeConversion(self, *args): pass class _JPackage: def __init__(self, *args, **kwargs): pass # Monkey patch (this is needed to catch errors for missing TypeMock) m = mock.Mock.__getattr__ def patch(self, key): if key == "__name__": return "FIXME TypeMock is missing" return m(self, key) mock.Mock.__getattr__ = patch mockModule = mock.MagicMock() mockModule.isStarted = mock.Mock(return_value=False) mockModule._JArray = TypeMock("_JArray") mockModule._JClass = _JClass mockModule._JField = TypeMock("_JField") mockModule._JMethod = TypeMock("_JMethod") mockModule._JObject = TypeMock("_JObject") mockModule._JProxy = TypeMock("_JProxy") mockModule._JException = TypeMock("_JException") mockModule._JPackage = _JPackage mockModule._JClassHints = _JClassHints mockModule._hasClass = lambda x: False sys.modules['_jpype'] = mockModule import jpype import jpype.imports # For some reason jpype.imports does not work if called in sphinx. Importing # it here solved the problem. version = jpype.__version__ # The full version, including alpha/beta/rc tags. release = jpype.__version__ # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all # documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. #keep_warnings = False # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # on_rtd is whether we are on readthedocs.org, this line of code grabbed from docs.readthedocs.org on_rtd = os.environ.get('READTHEDOCS', None) == 'True' if not on_rtd: # only import and set the theme if we're building docs locally import sphinx_rtd_theme html_theme = 'sphinx_rtd_theme' html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] # otherwise, readthedocs.org uses their theme by default, so no need to specify it # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. html_logo = 'logo.png' # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] html_context = { 'css_files': [ '_static/theme_overrides.css', # override wide tables in RTD theme ], } # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. #html_extra_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'JPypedoc' # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # 'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). # 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. # 'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ ('index', 'JPype.tex', u'JPype Documentation', u'Steve Menard, Luis Nell and others', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'jpype', u'JPype Documentation', [u'Steve Menard, Luis Nell and others'], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'JPype', u'JPype Documentation', u'Steve Menard, Luis Nell and others', 'JPype', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False napoleon_custom_sections = ["Static Methods", "Virtual Methods", "Constructors"] jpype-1.3.0/doc/dbapi2.rst000066400000000000000000000437001405671516700153220ustar00rootroot00000000000000################## JPype DBAPI2 Guide ################## `Introduction` ============== One common use of JPype is to provide access to databases used JDBC. The JDBC API is well established, very capable, and supports most databases. JPype can be used to access JDBC both directly or through the use of the Python DBAPI2 as layed (see PEP-0249_). Unfortunately, the Python API leaves a lot of behaviors undefined. The JPype dbapi2 module provides our implementation of this Python API. Normally the Python API has to deal with two different type systems, Python and SQL. When using JDBC, we have the added complexity that Java types are used to communicate with the driver. We have introduced concepts appropriate to handle this addition complexity. `Module Interface` ================== `Constructors` -------------- Access to the database is made available through connection objects. The module provides the following constructor for connections: .. _connect: .. autofunction:: jpype.dbapi2.connect Globals ------- JPype dbapi2 defines several globals that define the module behavior. These values are constants. .. _apilevel: `apilevel`_ The apilevel for the module is "``2.0``". .. _threadsafety: `threadsafety`_ The threadsafety level is 2 meaning "Threads may share the module and connections". But the actual threading level depends on the driver implementation that JDBC is connected to. Connections for many databases are synchronized so they can be shared, but threads must execute statement in series. Connections in the module are implemented in Python and have per object resources that cannot be shared. Attempting to use a connection with a thread other than the thread that created it will raise an ``Error``. Sharing in the above context means that two threads may use a resource without wrapping it using a mutex semaphore to implement resource locking. Note that you cannot always make external resources thread safe by managing access using a mutex: the resource may rely on global variables or other external sources that are beyond your control. .. _paramstyle: `paramstyle`_ The parameter style for JPype dbapi2 module is ``qmark`` ============ ============================================================== paramstyle Meaning ============ ============================================================== ``qmark`` Question mark style, e.g. ``...WHERE name=?`` ============ ============================================================== Exceptions ---------- The dbapi2 module exposes error information using the following exceptions: .. autoclass:: jpype.dbapi2.Warning .. autoclass:: jpype.dbapi2.Error .. autoclass:: jpype.dbapi2.InterfaceError .. autoclass:: jpype.dbapi2.DatabaseError .. autoclass:: jpype.dbapi2.DataError .. autoclass:: jpype.dbapi2.OperationalError .. autoclass:: jpype.dbapi2.IntegrityError .. autoclass:: jpype.dbapi2.InternalError .. autoclass:: jpype.dbapi2.ProgrammingError .. autoclass:: jpype.dbapi2.NotSupportedError Python exceptions are more fine grain than JDBC exceptions. Whereever possible we have redirected the Java exception to the nearest Python exception. However, there are cases in which the Java exception may appear. Those exceptions inherit from `:py:class:jpype.dbapi2.Error`. This is the exception inheritance layout:: Exception |__Warning |__Error |__InterfaceError |__java.sql.SQLError | |__java.sql.BatchUpdateException | |__java.sql.RowSetWarning | |__java.sql.SerialException | |__java.sql.SQLClientInfoException | |__java.sql.SQLNonTransientException | |__java.sql.SQLRecoverableException | |__java.sql.SQLTransientException | |__java.sql.SQLWarning | |__java.sql.SyncFactoryException | |__java.sql.SyncProviderException | |__DatabaseError |__DataError |__OperationalError |__IntegrityError |__InternalError |__ProgrammingError |__NotSupportedError Type Access =========== JPype dbapi2 provides two different maps which serve to convert data between Python and SQL types. When setting parameters and fetching results, Java types are used. The connection provides to maps for converting the types of parameters. An `adapter `_ is used to translate from a Python type into a Java type when setting a parameter. Once a result is produced, a `converter `_ can be used to translate the Java type back into a Python type. There are two lookup functions that select the behavior to decide how a column or parameter should be treated. These are `getters`_ and `setters`_. .. _adapters: adapters_ --------- Whenever a Python type is passed to a statement, it must first be converted to the appropriate Java type. This can be accomplished in a few ways. The user can manually convert to the correct type by constructing a Java object or applying the JPype casting operator. Some Java types have built in implicit conversions from the corresponding type. For all other conversions, an adapter. An adapter is defined as a type to convert from and a conversion function which takes a single argument that returns a Java object. The adapter maps are stored in the connection. The adapter map can be supplied when calling `connect`_ , or added to the map later through the `adapters `_ property. .. _setters: setters_ -------- A setter transfers the Java type into a SQL parameter. There are multiple types can an individual parameter may accept. The type of setter is determined by the JDBC type. Each individual JDBC type can have its own setter. Not every database supports the same setter. There is a default setter may that would work for most purposes. Setters can also be set individually using the ``types`` argument to the ``.execute*()`` methods. The setter is a function which processes the database metadata into a type. Setters can supplied as a map to `connect`_ or by accessing the `setter `_ property on a Connection. .. autofunction:: jpype.dbapi2.SETTERS_BY_META .. autofunction:: jpype.dbapi2.SETTERS_BY_TYPE .. _converters: converters_ ----------- When a result is fetched the database, it is returned as Jave type. This Java type then has a converter applied. Converters are stored in a map holding the type as key and a converter function that takes one argument and returns the desired type. The default converter map will convert all types to Python. This can be disabled by setting the converters to ``None``. The converter map can be passed in to the `connect`_ function, or set on the Connection using the `converters `_ property. It can be supplied as a list or a map to the ``.fetch*()`` methods. .. _getters: getters_ -------- JDBA provides more than one way to access data returned from a result. In the native JDBC, each executed statement returns a result set which acts as a cursor for the statement. It is possible to access each column using a different get method. The default map will attempt to fetch according to the most general type. The getter is a configurable function that uses the metadata to find the most appropriate type. .. autofunction:: jpype.dbapi2.GETTERS_BY_TYPE .. autofunction:: jpype.dbapi2.GETTERS_BY_NAME .. _Connection: `Connection Objects`_ ===================== A Connection object can be created using the using `connect`_ function. Once a connection is established the resulting Connection contains the following. .. autoclass:: jpype.dbapi2.Connection :members: .. _Cursor: `Cursor Objects`_ ================= These objects represent a database cursor, which is used to manage the context of a fetch operation. Cursors created from the same connection are not isolated, *i.e.*, any changes done to the database by a cursor are immediately visible by the other cursors. Cursors created from different connections may or may not be isolated, depending on how the transaction support is implemented (see also the connection's `rollback `_ and `commit `_ methods). .. autoclass:: jpype.dbapi2.Cursor :members: Cursors can act as an iterator. So to get the contents of table one could use code like: .. code-block:: python with connection.cursor() as cur: cur.execute("select * from table") for row in cur: print(row) `SQL Type Constructors` ======================= Many databases need to have the input in a particular format for binding to an operation's input parameters. For example, if an input is destined for a ``DATE`` column, then it must be bound to the database in a particular string format. Similar problems exist for "Row ID" columns or large binary items (e.g. blobs or ``RAW`` columns). This presents problems for Python since the parameters to the `.execute*()` method are untyped. When the database module sees a Python string object, it doesn't know if it should be bound as a simple `CHAR` column, as a raw `BINARY` item, or as a `DATE`. This is less of a problem in JPype dbapi2 than in a typically dbapi driver as we have strong typing backing the connection, but we are still required to supply methods to construct individual SQL types. These functions are: .. autofunction:: jpype.dbapi2.Date .. autofunction:: jpype.dbapi2.Time .. autofunction:: jpype.dbapi2.Timestamp .. autofunction:: jpype.dbapi2.DateFromTicks .. autofunction:: jpype.dbapi2.TimeFromTicks .. autofunction:: jpype.dbapi2.TimestampFromTicks .. autofunction:: jpype.dbapi2.Binary For the most part these constructors are largely redundant as adapters can provide the same functionality and Java types can directly use to communicate type information. .. `JDBC Types` `JDBC Types`_ ============= In the Python DBAPI2, the SQL type system is normally reduced to a subset of the SQL types by mapping multiple types together for example ``STRING`` covers the types `STRING`, `CHAR`, `NCHAR` , `NVARCHAR` , `VARCHAR`, and `OTHER`. JPype dbapi2 supports both the recommended Python types and the fine grain JDBC types. Each type is represented by an object of type JBDCType. .. autoclass:: jpype.dbapi2.JDBCType :members: The following types are defined with the correspond Python grouping, the default setter, getter, and Python type. For types that support more than one type of getter, the special getter can be applied as the converter for the type. For example, the defaulf configuration has ``getter[BLOB] = BINARY.get``, to get the Blob type use ``getter[BLOB] = BLOB.get`` or specify it when calling `use `_. ======== ======================== =================== ============== ================= =============== Group JDBC Type Default Getter Default Setter PyTypes Special Getter ======== ======================== =================== ============== ================= =============== DATE DATE getDate setDate datetime.datetime DATETIME TIMESTAMP getTimestamp setTimestamp datetime.datetime TIME TIME getTime setTime datetime.datetime -------- ------------------------ ------------------- -------------- ----------------- --------------- DECIMAL DECIMAL getBigDecimal setBigDecimal decimal.Decimal DECIMAL NUMERIC getBigDecimal setBigDecimal decimal.Decimal -------- ------------------------ ------------------- -------------- ----------------- --------------- FLOAT FLOAT getDouble setDouble float FLOAT DOUBLE getDouble getDouble float FLOAT REAL getFloat setFloat float -------- ------------------------ ------------------- -------------- ----------------- --------------- NUMBER BOOLEAN getBoolean setBoolean bool NUMBER BIT getBoolean setBoolean bool NUMBER TINYINT (0..255) getShort setShort int NUMBER SMALLINT (-2^15..2^15) getShort getShort int NUMBER INTEGER (-2^31..2^31) getInt getInt int NUMBER BIGINT (-2^63..2^63) getLong getLong int -------- ------------------------ ------------------- -------------- ----------------- --------------- BINARY BINARY getBytes setBytes bytes BINARY BLOB getBytes setBytes bytes getBlob BINARY LONGVARBINARY getBytes setBytes bytes BINARY VARBINARY getBytes setBytes bytes -------- ------------------------ ------------------- -------------- ----------------- --------------- TEXT CLOB getString setString str getClob TEXT LONGNVARCHAR getString setString str TEXT LONGVARCHAR getString setString str TEXT NCLOB getString setString str getNClob TEXT SQLXML getString setString str getSQLXML -------- ------------------------ ------------------- -------------- ----------------- --------------- STRING NVARCHAR getString setString str STRING CHAR getString setString str STRING NCHAR getString setString str STRING VARCHAR getString setString str -------- ------------------------ ------------------- -------------- ----------------- --------------- ARRAY getObject getArray OBJECT getObject getObject NULL getObject getObject REF getObject getRef ROWID getObject getRowId RESULTSET getObject getObject TIME_WITH_TIMEZONE getObject getTime TIMESTAMP_WITH_TIMEZONE getObject getTimeStamp -------- ------------------------ ------------------- -------------- ----------------- --------------- * ASCII_STREAM getAsciiStream * BINARY_STREAM getBinaryStream * CHARACTER_STREAM getCharacterStream * ASCII_STREAM getAsciiStream * BINARY_STREAM getBinaryStream * CHARACTER_STREAM getCharacterStream * NCHARACTER_STREAM getNCharacterStream * URL getURL ======== ======================== =================== ============== ================= =============== Some of these types never correspond to a SQL type but are used only to specify getters and setters for a particular parameter or column. Other ----- The default getter will attempt to look for the column type by name if the type is OTHER. This allows for user defined types to be added if supported by the database. User defined types ------------------ A user can declare a new type using ``JDBCType``. The arguments are the name of new type which must match a SQL typename. Use ``typeinfo`` on the connection to get the list of available types. It may necessary to define a custom getter function which defining a new type so that the custom return type accurately reflects the column type. .. code-block:: python class JSONType(dbapi2.JDBCType): def get(self, *args): rc = JDBCType.get(self, *args) # Custom return converter here return rc JSON = JSONType("JSON") Conclusion ========== This wraps up the JPype dbapi2 module. Because JDBC supports many different dataase drivers, not every behavior is defined on every driver. Consult the driver specific information to determine what is available. The dbapi2 does not fully cover all of the capabilities of the JDBC driver. To access functions that are not defined in DBAPI2, the JDBC native objects can be accessed on both the connection and the cursor objects. .. _PEP-0249: https://www.python.org/dev/peps/pep-0249/ .. _connection.rollback: #jpype.dbapi2.Connection.rollback .. _connection.commit: #jpype.dbapi2.Connection.commit .. _connection.adapters: #jpype.dbapi2.JDBCType.adapters .. _connection.setters: #jpype.dbapi2.JDBCType.setters .. _connection.converters: #jpype.dbapi2.JDBCType.converters .. _cursor.use: #jpype.dbapi2.Cursor.use .. _cursor.description: #jpype.dbapi2.Cursor.description .. _jdbctype.adapters: #jpype.dbapi2.Connection.adapters jpype-1.3.0/doc/develguide.rst000066400000000000000000001401771405671516700163040ustar00rootroot00000000000000Developer Guide =============== Overview -------- This document describes the guts of jpype. It is intended lay out the architecture of the jpype code to aid intrepid lurkers to develop and debug the jpype code once I am run over by a bus. For most of this document I will use the royal we, except where I am giving personal opinions expressed only by yours truly, the author Thrameos. History ~~~~~~~ When I started work on this project it had already existed for over 10 years. The original developer had intended a much larger design with modules to support multiple languages such as Ruby. As such it was constructed with three layers of abstraction. It has a wrapper layer over Java in C++, a wrapper layer for the Python api in C++, and an abstraction layer intended to bridge Python and other interpreted languages. This multilayer abstraction ment that every debugging call had to drop through all of those layers. Memory management was split into multiple pieces with Java controlling a portion of it, C++ holding a bunch of resources, Python holding additional resources, and HostRef controlling the lifetime of objects shared between the layers. It also had its own reference counting system for handing Java references on a local scale. This level of complexity was just about enough to scare off all but the most hardened programmer. Thus I set out to eliminate as much of this as I could. Java already has its own local referencing system to deal in the form of LocalFrames. It was simply a matter of setting up a C++ object to hold the scope of the frames to eliminate that layer. The Java abstraction was laid out in a fashion somewhat orthagonally to the Java inheritance diagram. Thus that was reworked to something more in line which could be safely completed without disturbing other layers. The multilanguage abstraction layer was already pierced in multiple ways for speed. However, as the abastraction interwove throughout all the library it was a terrible lift to remove and thus required gutting the Python layer as well to support the operations that were being performed by the HostRef. The remaining codebase is fairly slim and reasonably streamlined. This rework cut out about 30% of the existing code and sped up the internal operations. The Java C++ interface matches the Java class hierachy. Architecture ~~~~~~~~~~~~ JPype is split into several distinct pieces. ``jpype`` Python module The majority of the front end logic for the toolkit is in Python jpype module. This module deals with the construction of class wrappers and control functions. The classes in the layer are all prefixed by ``J``. ``_jpype`` CPython module The native module is supported by a CPython module called ``_jpype``. The ``_jpype`` module is located in ``native/python`` and has C style classes with a prefix ``PyJP``. This CPython layer acts as a front end for passing to the C++ layer. It performs some error checking. In addition to the module functions in ``_JModule``, the module has multiple Python classes to support the native jpype code such as ``_JClass``, ``_JArray``, ``_JValue``, ``_JValue``, etc. CPython API wrapper In addition to the exposed Python module layer, there is also a C++ wrapper for the Python API. This is located in ``native/python`` and has the prefix ``JPPy`` for all classes. ``jp_pythontypes`` wraps the required parts of the CPython API in C++ for use in the C++ layer. C++ JNI layer The guts that drive Java are in the C++ layer located in ``native/common``. This layer has the namespace ``JP``. The code is divided into wrappers for each Java type, a typemanager for mapping from Java names to class instances, support classes for proxies, and a thin JNI layer used to help ensure rigerous use of the same design patterns in the code. The primary responsibility of this layer is type conversion and matching of method overloads. Java layer In addition to the C++ layer, jpype has a native Java layer. This code is compiled as a "thunk" which is loaded into the JVM in the form of a a binary stored as a string. Code for Java is found in ``native/java``. The Java layer is divided into two parts, a bootstrap loader and a jar containing the support classes. The Java layer is responsible managing the lifetime of shared Python, Java, and C++ objects. ``jpype`` module ----------------- The ``jpype`` module itself is made of a series of support classes which act as factories for the individual wrappers that are created to mirror each Java class. Because it is not possible to wrap all Java classes with staticly created wrappers, instead jpype dynamically creates Python wrappers as requested by the user. The wrapping process is triggered in two ways. The user can manually request creating a class by importing a class wrapper with jpype.imports or ``JPackage`` or by manually invoking it with ``JClass``. Or the class wrapper can be created automatically as a result of a return type or exception thrown to the user. Because the classes are created dynamically, the class structure uses a lot of Python meta programming. Each class wrapper derives from the class wrappers of each of the wrappers corresponding to the Java classes that each class extends and implements. The key to this is to hacked ``mro``. The ``mro`` orders each of the classes in the tree such that the most drived class methods are exposed, followed by each parent class. This must be ordered to break ties resulting from multiple inheritance of interfaces. The factory classes are grafted into the type system using ``__instancecheck__`` and ``__subtypecheck__``. resource types ~~~~~~~~~~~~~~ JPype largely maps to the same concepts as Python with a few special elements. The key concept is that of a Factory which serves to create Java resources dynamically as requested. For example there is no Python notation to create a ``int[][]`` as the concept of dimensions are fluid in Python. Thus a factory type creates the actual object instance type with ``JArray(JInt,2)`` Like Python objects, Java objects derives from a type object which is called ``JClass`` that serves as a meta type for all Java derived resources. Additional type like object ``JArray`` and ``JInterface`` serve to probe the relationships between types. Java object instances are created by calling the Java class wrapper just like a normal Python class. A number of pseudo classes serve as placeholders for Java types so that it is not necessary to create the type instance when using. These aliased classes are ``JObject``, ``JString``, and ``JException``. Underlying all Java instances is the concept of a ``jvalue``. ``jvalue`` ++++++++++ In the earlier design, wrappers, primitives and objects were all seperate concepts. At the JNI layer these are unified by a common element called jvalue. A ``jvalue`` is a union of all primitives with the jobject. The jobject can represent anything derived from Java object including the pseudo class jstring. This has been replaced with a Java slot concept which holds an instance of ``JPValue`` which holds a pointer to the C++ Java type wrapper and a Java jvalue union. We will discuss this object further in the CPython section. .. _bootstrapping: Bootstrapping ~~~~~~~~~~~~~ The most challenging part in working with the jpype module other than the need to support both major Python versions with the same codebase is the bootstrapping of resources. In order to get the system working, we must pass the Python resources so the ``_jpype`` CPython module can acquire resources and then construct the wrappers for ``java.lang.Object`` and ``java.lang.Class``. The key difficulty is that we need reflection to get methods from Java and those are part of ``java.lang.Class``, but class inherits from ``java.lang.Object``. Thus Object and the interfaces that Class inherits must all be created blindly. The order of bootstrapping is controlled by specific sequence of boot actions after the JVM is started in ``startJVM``. The class instance ``class_`` may not be accessed until after all of the basic class, object, and exception types have been loaded. Factories ~~~~~~~~~ The key objects exposed to the user (``JClass``, ``JObject``, and ``JArray``) are each factory meta classes. These classes serve as the gate keepers to creating the meta classes or object instances. These factories inherit from the Java class meta and have a ``class_`` instance inserted after the the JVM is started. They do not have exposed methods as they are shadows for action for actual Java types. The user calls with the specified arguments to create a resource. The factory calls the ``__new__`` method when creating an instance of the derived object. And the C++ wrapper calls the method with internally construct resource such as ``_JClass`` or ``_JValue``. Most of the internal calls currently create the resource directly without calling the factories. The gateway for this is ``PyJPValue_create`` which delegates the process to the corresponding specialized type. Style ~~~~~ One of the aspects of the jpype design is elegance of the factory patterns. Rather than expose the user a large number of distinct concepts with different names, the factories provide powerfull functionality with the same syntax for related things. Boxing a primitive, casting to a specific type, and creating a new object are all tied together in one factory, ``JObject``. By also making that factory an effective base class, we allow it to be used for ``issubtype`` and ``isinstance``. This philosophy is further enhanced by silent customizers which integrate Python functionality into the wrappers such that Java classes can be used effectively with Python syntax. Consistent use and misuse of Python concepts such as ``with`` for defining blocks such as try with resources and synchronized hide the underlying complexity and give the feeling to the user that the module is integrated completely as a solution such as jython. When adding a new feature to the Python layer, consider carefully if the feature needs to be exposed a new function or if it can be hidden in the normal Python syntax. JPype does somewhat break the Python naming conventions. Because Java and Python have very different naming schemes, at least part of the kit would have a different convention. To avoid having one portion break Python conventions and another part conform, we choose to use Java notation consistently throughout. Package names should be lower with underscores, classes should camel case starting upper, functions and method should be camel case starting lower. All private methods and classes start with a leading underscore and are not exported. Customizers ~~~~~~~~~~~ There was a major change in the way the customizers work between versions. The previous system was undocumented and has now been removed, but as someone may have used of it previously, we will contrast it with the revised system so that the customizers can be converted. In the previous system, a global list stored all customizers. When a class was created, it went though the list and asked the class if it matched that class name. If it matched, it altered the dict of members to be created so when the dynamic class was finished it had the custome behavior. This system wasn't very scalable as each customizer added more work to the class construction process. The revised system works by storing a dictionary keyed to the class name. Thus the customizer only applies to the specific class targeted to the customizer. The customizer is specified using annotation of a prototype class making methods automatically copy onto the class. However, sometimes a customizer needs to be applied to an entire tree of classes such as all classes that implement ``java.util.List``. To handle this case, the class creation system looks for a special method ``__java_init__`` in the tree of base classes and calls it on the newly created class. Most of the time the customization was the same simple pattern so we added a ``sticky`` flag to build the initialization method directly. This method can alter the class to make it add the new behavior. Note the word alter. Where before we changed the member prior to creating the class, here we are altering the class. Thus the customizer is expected to monkey patch the existing class. There is only one pattern of monkey patching that works on both Python 2 and Python 3 so be sure to use the ``type.__setattr__`` method of altering the class dictionary. It is possible to apply customizers after the class has already been created because we operate by monkey patching. But there is a limitation that there can only be one ``__java_init__`` method and thus two customizers specifying a global behavior on the same class wrapper will lead to unexpected behavior. ``_jpype`` CPython module -------------------------- Diving deeper into the onion, we have the Python front end. This is divided into a number of distinct pieces. Each piece is found under ``native/python`` and is named according to the piece it provides. For example, ``PyJPModule`` is found in the file ``native/python/pyjp_module.cpp`` Earlier versions of the module had all of the functionality in the modules global space. This functionality is now split into a number of classes. These classes each have a constructor that is used to create an instance which will correspond to a Java resource such as class, array, method, or value. Jpype objects work with the inner layers by inheriting from a set of special ``_jpype`` classes. This class hiarachy is mantained by the meta class ``_jpype._JClass``. The meta class does type hacking of the Python API to insert a reserved memory slot for the ``JPValue`` structure. The meta class is used to define the Java base classes: * ``_JClass`` - Meta class for all Java types which maps to a java.lang.Class extending Python type. * ``_JArray`` - Base class for all Java array instances. * ``_JObject`` - Base type of all Java object instances extending Python object. * ``_JNumberLong`` - Base type for integer style types extending Python int. * ``_JNumberFloat`` - Base type for float style types extending Python float. * ``_JNumberChar`` - Special wrapper type for JChar and java.lang.Character types extending Python float. * ``_JException`` - Base type for exceptions extending Python Exception. * ``_JValue`` - Generic capsule representing any Java type or instance. These types are exposed to Python to implement Python functionality specific to the behavior expected by the Python type. Under the hood these types are largely ignored. Instead the internal calls for the Java slot to determine how to handle the type. Therefore, internally often Python methods will be applied to the "wrong" type as the requirement for the method can be satisfied by any object with a Java slot rather than a specific type. See the section regarding Java slots for details. ``PyJPModule`` module ~~~~~~~~~~~~~~~~~~~~~~ This is the front end for all the global functions required to support the Python native portion. Most of the functions provided in the module are for control and auditing. Resources are created by setting attributes on the ``_jpype`` module prior to calling ``startJVM``. When the JVM is started each of th required resources are copied from the module attribute lists to the module internals. Setting the attributes after the JVM is started has no effect. Resources are verified to exist when the JVM is started and any missing resource are reported as an error. ``_JClass`` class ~~~~~~~~~~~~~~~~~~~ The class wrappers have a metaclass ``_jpyep._JClass`` which serves as the guardian to ensure the slot is attached, provide for the inheritance checks, and control access to static fields and methods. The slot holds a java.lang.Class instance but it does not have any of the methods normally associate with a Java class instance exposed. A java.lang.Class instance can be converted to a Jave class wrapper using ``JClass``. ``_JMethod`` class ~~~~~~~~~~~~~~~~~~~~ This class acts as descriptor with a call method. As a descriptor accessing its methods through the class will trigger its ``__get__`` function, thus getting ahold of it within Python is a bit tricky. The ``__get__`` mathod is used to bind the static unbound method to a particular object instance so that we can call with the first argument as the ``this`` pointer. It has some reflection and diagnostics methods that can be useful it tracing down errors. The beans methods are there just to support the old properties API. The naming on this class is a bit deceptive. It does not correspond to a single method but rather all the overloads with the same name. When called it passes to with the arguments to the C++ layer where it must be resolved to a specific overload. This class is stored directly in the class wrappers. ``_JField`` class ~~~~~~~~~~~~~~~~~~~ This class is a descriptor with ``__get__`` and ``__set__`` methods. When called at the static class layer it operates on static fields. When called on a Python object, it binds to the object making a ``this`` pointer. If the field is static, it will continue to access the static field, otherwise, it will provide access to the member field. This trickery allows both static and member fields to wrap as one type. This class is stored directly in the class wrappers. ``_JArray`` class ~~~~~~~~~~~~~~~~~~~ Java arrays are extensions of the Java object type. It has both methods associated with java.lang.Object and Python array functionality. Primitives have specialized implementations to allow for the Python buffer API. ``_JMonitor`` class ~~~~~~~~~~~~~~~~~~~~~ This class provides ``synchronized`` to JPype. Instances of this class are created and held using ``with``. It has two methods ``__enter__`` and ``__exit__`` which hook into the Python RAII system. ``_JValue`` class ~~~~~~~~~~~~~~~~~~~ Java primitive and object instance derive from special Python derived types. These each have the Python functionality to be exposed and a Java slot. The most generic of these is ``_JValue`` which is simply a capsule holding the Java C++ type wrapper and a Java jvalue union. CPython methods for the ``PyJPValue`` apply to all CPython objects that hold a Java slot. Specific implementation exist for object, numbers, characters, and exceptions. But fundimentally all are treated the same internally and thus the CPython type is effectively erased outside of Python. Unlike ``jvalue`` we hold the object type in the C++ ``JPValue`` object. The class reference is used to determine how to match the arguments to methods. The class may not correspond to the actual class of the object. Using a class other than the actual class serves to allow an object to be cast and thus treated like another type for the purposes of overloading. This mechanism is what allows the ``JObject`` factory to perform a typecast to make an object instance act like one of its base classes.. .. _javaslots: Java Slots ------------------ THe key to achieving reasonable speed within CPython is the use of slots. A slot is a dedicated memory location that can be accessed without consulting the dictionary or bases of an object. CPython achieve this by reserving space within the type structure and by using a set of bit flags so that it can avoid costly. The reserved space in order by number and thus avoids the need to access the dictionary while the bit flags serve to determine the type without traversing the ``__mro__`` structure. We had to implement the same effect which deriving from a wide variety for Python types including type, object, int, long, and Exception. Adding the slot directly to the type and objects base memory does not work because these types all have different memory layouts. We could have a table look up based on the type but because we must obey both the CPython and the Java object hierarchy at the same time it cannot be done within the memory layout of Python objects. Instead we have to think outside the box, or rather outside the memory footprint of Python objects. CPython faces the same conflict internally as inheritance often forces adding a dictionary or weak reference list onto a variably size type sych as long. For those cases it adds extract space to the basesize of the object and then ignores that space for the purposes of checking inheritance. It pairs this with an offset slot that allows for location of the dynamic placed slots. We cannot replicate this in the same way because the CPython interals are all specialize static members and there is no provision for introducting user defined dynamic slots. Therefore, instead we will add extra memory outside the view of Python objects though the use of a custom allocator. We intercept the call to create an object allocation and then call the regular Python allocators with the extra memory added to the request. As our extrs slot has resource in the form of Java global references associated with it, we must deallocate those resource regardless of the type that has been extended. We perform this task by creating a custom finalize method to serve as the destructor. Thus a Java slot requires overriding each of ``tp_alloc``, ``tp_free`` and ``tp_finalize``. The class meta gatekeeper creates each type and verifies that the required hooks are all in place. If the user tries to bypass this it should produce an error. In place of Python bit flags to check for the presence of a Java slot we instead test the slot table to see if our hooks are in place. We can test if the slot is present by looking to see if both `tp_alloc` and `tp_finalize` point to our Java slot handlers. This means we are still effectively a slot as we can test and access with O(1). Accessing the slot requires testing if the slot exists for the object, then computing the sice of the object using the basesize and itemsize associate with the type and then offsetting the Python object pointer appropriately. The overall cost is O(1), though is slightly more heavy that directly accesssing an offset. CPython API layer ------------------ To make creation of the C++ layer easier a thin wrapper over the CPython API was developed. This layer provided for handling the CPython referencing using a smart pointer, defines the exception handling for Python, and provides resource hooks for duck typing of the ``_jpype`` classes. This layer is located with the rest of the Python codes in ``native/python``, but has the prefix ``JPPy`` for its classes. As the bridge between Python and C++, these support classes appear in both the ``_jpype`` CPython module and the C++ JNI layer. Exception handling ~~~~~~~~~~~~~~~~~~ A key piece of the jpype interaction is the transfer of exceptions from Java to Python. To accomplish this Python method that can result in a call to Java must have a ``try`` block around the contents of the function. We use a routine pattern of code to interact with Java to achieve this: .. code-block:: cpp PyObject* dosomething(PyObject* self, PyObject* args) { // Tell the logger where we are JP_PY_TRY("dosomething"); // Make sure there is a jvm to receive the call. ASSERT_JVM_RUNNING("dosomething"); // Make a resource to capture any Java local references JPJavaFrame frame; // Call our Java methods ... // Return control to Python return obj.keep(); // Use the standard catch to transfer any exceptions back // to Python JP_PY_CATCH(NULL); } All entry points from Python into ``_jpype`` should be guarded with this pattern. There are exceptions to this pattern such as removing the logging, operating on a call that does not need the JVM running, or operating where the frame is already supported by the method being called. Python referencing ~~~~~~~~~~~~~~~~~~ One of the most miserable aspects of programming with CPython is the relative inconsistancy of referencing. Each method in Python may use a Python object or steal it, or it may return a borrowed reference or give a fresh reference. Similar command such as getting an element from a list and getting an element from a tuple can have different rules. This was a constant source of bugs requiring consultation of the Python manual for every line of code. Thus we wrapped all of the Python calls we were required to work with in ``jp_pythontypes``. Included in this wrapper is a Python reference counter called ``JPPyObject``. Whenever an object is returned from Python it is immediately placed in smart pointer ``JPPyObject`` with the policy that it was created with such as ``use_``, ``borrowed_``, ``claim_`` or ``call_``. ``use_`` This policy means that the reference counter needs to be incremented and the start and the end. We must reference it because if we don't and some Python call destroys the refernce out from under us, the system may crash and burn. ``borrowed_`` This policy means we were to be give a borrowed reference that we are expected to reference and unreference when complete, but the command that returned it can fail. Thus before reference it, the system must check if an error has occurred. If there is an error, it is promoted to an exception. ``claim_`` This policy is used when we are given a new object with is already referenced for us. Thus we are to steal the reference for the duration of our use and then dereference when we are done to keep it from leaking. ``call_`` This policy both steals the reference and verifies there were no errors prior to continuing. Errors are promoted to exceptions when this reference is created. If we need to pass an object which is held in a smart pointer to Python which requires a reference, we call keep on the reference which transfers control to a ``PyObject*`` and prevents the pointer from removing the reference. As the object handle is leaving our control keep should only be called the return statement. The smart pointer is not used on method passing in which the parent explicitly holds a reference to the Python object. As all tuples passed as arguments operate like this, that means much of the API accepts bare ``PyObject*`` as arguments. It is the job of the caller to hold the reference for its scope. On CPython extensions ~~~~~~~~~~~~~~~~~~~~~ CPython is somewhat of a nightmare to program in. It is not that they did not try to document the API, but it is darn complex. The problems extend well beyond the reference counting system that we have worked around. In particular, the object model though well developed is very complex, often to get it to work you must follow letter for letter the example on the CPython user guide, and even then it may all go into the ditch. The key problem is that there are a lot of very bad examples of how to write CPython extension modules out there. Often the these examples bypass the appropriate macro and just call the field, or skip the virtual table and try to call the Python method directly. It is true that these things do not break there example, but they are conditioned on these methods they are calling directly to be the right one for the job, but depends a lot on what the behavior of the object is supposed to be. Get it wrong and you get really nasty segfault. CPython itself may be partly responsible for some of these problems. They generally seem to trust the user and thus don't verify if the call makes sense. It is true that it will cost a little speed to be aggressive about checking the type flags and the allocator match, but not checking when the error happens, means that it fails far from the original problem source. I would hope that we have moved beyond the philosophy that the user should just to whatever they want so it runs as fast as possible, but that never appears to be the case. Of course, I am just opining from the outside of the tent and I am sure the issues are much more complicated it appears superficially. Then again if I can manage to provide a safe workspace while juggling the issues of multiple virtual machines, I am free to have opinions on the value of trading performance and safety. In short when working on the extension code, make sure you do everything by the book, and check that book twice. Always go through the types virtual table and use the propery macros to access the resources. Miss one line in some complex pattern even once and you are in for a world of hurt. There are very few guard rails in the CPython code. C++ JNI layer ------------- The C++ layer has a number of tasks. It is used to load thunks, call JNI methods, provide reflection of classes, determine if a conversion is possible, perform conversion, match arguments to overloads, and convert return values back to Java. Memory management ~~~~~~~~~~~~~~~~~ Java provides built in memory management for controlling the lifespan of Java objects that are passed through JNI. When a Java object is created or returned from the JVM it returns a handle to object with a reference counter. To manage the lifespan of this reference counter a local frame is created. For the duration of this frame all local references will continue to exist. To extend the lifespan either a new global reference to the object needs to be created, or the object needs to be kept. When the local frame is destroyed all local references are destroyed with the exception of an optional specified local return reference. We have wrapped the Java reference system with the wrapper ``JPLocalFrame``. This wrapper has three functions. It acts as a RAII (Resource acquisition is initialization) for the local frame. Further, as creating a local frame requires creating a Java env reference and all JNI calls require access to the env, the local frame acts as the front end to call all JNI calls. Finally as getting ahold of the env requires that the thread be attached to Java, it also serves to automatically attach threads to the JVM. As accessing an unbound thread will cause a segmentation fault in JNI, we are now safe from any threads created from within Python even those created outside our knowledge. (I am looking at you spyder) Using this pattern makes the JPype core safe by design. Forcing JNI calles to be called using the frame ensures: - Every local reference is destroyed. - Every thread is properly attached before JNI is used. - The pattern of keep only one local reference is obeyed. To use a local frame, use the pattern shown in this example. .. code-block:: cpp jobject doSomeThing(std::string args) { // Create a frame at the top of the scope JPLocalFrame frame; // Do the required work jobject obj =frame.CallObjectMethodA(globalObj, methodRef, params); // Tell the frame to return the reference to the outer scope. // once keep is called the frame is destroyed and any // call will fail. return frame.keep(obj); } Note that the value of the object returned and the object in the function will not be the same. The returned reference is owned by the enclosing local frame and points to the same object. But as its lifespan belongs to the outer frame, its location in memory is different. You are allowed to ``keep`` a reference that was global or was passed in, in either of those case, the outer scope will get a new local reference that points to the same object. Thus you don't need to track the origin of the object. The changing of the value while pointing is another common problem. A routine error is to get a local reference, call ``NewGlobalRef`` and then keeping the local reference rather than the shiny new global reference it made. This is not like the Python reference system where you have the object that you can ref and unref. Thus make sure you always store only the global reference. .. code-block:: cpp jobject global; // we are getting a reference, may be local, may be global. // either way it is borrowed and it doesn't belong to us. void elseWhere(jvalue value) { JPLocalFrame frame; // Bunch of code leading us to decide we need to // hold the resource longer. if (cond) { // okay we need to keep this reference, so make a // new global reference to it. global = frame.NewGlobalRef(value.l); } } But don't mistake this as an invitation to make global references everywhere. Global reference are global, thus will hold the member until the reference is destroyed. C++ exceptions can lead to missing the unreference, thus global references should only happen when you are placing the Java object into a class member variable or a global variable. To help manage global references, we have ``JPRef<>`` which holds a global reference for the duration of the C++ lifespace. This is the base class for each of the global reference types we use. .. code-block:: cpp typedef JPRef JPClassRef; typedef JPRef JPObjectRef; typedef JPRef JPArrayRef; typedef JPRef JPThrowableRef; For functions that expect the outer scope to already have created a frame for this context, we use the pattern of extending the outer scope rather than creating a new one. .. code-block:: cpp jobject doSomeThing(JPLocalFrame& frame, std::string args) { // Do the required work jobject obj = frame.CallObjectMethodA(globalObj, methodRef, params); // We must not call keep here or we will terminate // a frame we do not own. return obj; } Although the system we have set up is "safe by design", there are things that can go wrong is misused. If the caller fails to create a frame prior to calling a function that returns a local reference, the reference will go into the program scoped local references and thus leak. Thus, it is usually best to force the user to make a scope with the frame extension pattern. Second, if any JNI references that are not kept or converted to global, it becomes invalid. Further, since JNI recycles the reference pointer fairly quickly, it most likely will be pointed to another object whose type may not be expected. Thus, best case is using the stale reference will crash and burn. Worse case, the reference will be a live reference to another object and it will produce an error which seems completely irrelevant to anything that was being called. Horrible case, the live object does not object to bad call and it all silently proceeds down the road another two miles before coming to flaming death. Moral of the story, always create a local frame even if you are handling a global reference. If passed or returned a reference of any kind, it is a borrowed reference belonging to the caller or being held by the current local frame. Thus it must be treated accordingly. If you have to hold a global use the appropraite ``JPRef`` class to ensure it is exception and dtor safe. For further information read ``native/common/jp_javaframe.h``. Type wrappers ~~~~~~~~~~~~~ Each Java type has a C++ wrapper class. These classes provide a number of methods. Primitives each have their own unit type wrapper. Object, arrays, and class instances share a C++ wrapper type. Special instances are used for ``java.lang.Object`` and ``java.lang.Class``. The type wrapper are named for the class they wrap such as ``JPIntType``. Type conversion ++++++++++++++++ For type conversion, a C++ class wrapper provides four methods. ``canConvertToJava`` This method must consult the supplied Python object to determine the type and then make a determination of whether a conversion is possible. It reports ``none_`` if there is no possible conversion, ``explicit_`` if the conversion is only acceptable if forced such as returning from a proxy, ``implicit_`` if the conversion is possible and acceptable as part of an method call, or ``exact_`` if this type converts without ambiguity. It is excepted to check for something that is already a Java resource of the correct type such as ``JPValue``, or something this is implementing the behavior as an interface in the form of a ``JPProxy``. ``convertToJava`` This method consults the type and produces a conversion. The order of the match should be identical to the ``canConvertToJava``. It should also handle values and proxies. ``convertToPythonObject`` This method takes a jvalue union and converts it to the corresponding Python wrapper instance. ``getValueFromObject`` This converts a Java object into a ``JPValue`` corresponding. This unboxes primitives. Array conversion ++++++++++++++++++ In addition to converting single objects, the type rewrappers also serve as the gateway to working with arrays of the specified type. Five methods are used to work with arrays: ``newArrayInstance``, ``getArrayRange``, ``setArrayRange``, ``getArrayItem``, and ``setArrayItem``. Invocation and Fields ++++++++++++++++++++++ To convert a return type produced from a Java call, each type needs to be able to invoke a method with that return type. This corresponses the underlying JNI design. The methods invoke and invokeStatic are used for this purpose. Similarly accessing fields requires type conversion using the methods ``getField`` and ``setField``. Instance versus Type wrappers +++++++++++++++++++++++++++++++ Instances of individual Java classes are made from ``JPClass``. However, two special sets of conversion rules are required. These are in the form of specializations ``JPObjectBaseClass`` and ``JPClassBaseClass`` corresponding to ``java.lang.Object`` and ``java.lang.Class``. Support classes ~~~~~~~~~~~~~~~ In addition to the type wrappers, there are several support classes. These are: ``JPTypeManager`` The typemanager serves as a dict for all type wrappers created during the operation. ``JPReferenceQueue`` Lifetime manager for Java and Python objects. ``JPProxy`` Proxies implement a Java interface in Python. ``JPClassLoader`` Loader for Java thunks. ``JPEncoding`` Decodes and encodes Java UTF strings. ``JPTypeManager`` ++++++++++++++++++ C++ typewrappers are created as needed. Instance of each of the primitives along with ``java.lang.Object`` and ``java.lang.Class`` are preloaded. Additional instances are created as requested for individual Java classes. Currently this is backed by a C++ map of string to class wrappers. The typemanager provides a number lookup methods. .. code-block:: cpp // Call from within Python JPClass* JPTypeManager::findClass(const string& name) // Call from a defined Java class JPClass* JPTypeManager::findClass(jclass cls) // Call used when returning an object from Java JPClass* JPTypeManager::findClassForObject(jobject obj) ``JPReferenceQueue`` ++++++++++++++++++++ When a Python object is presented to Java as opposed to a Java object, the lifespan of the Python object must be extended to match the Java wrapper. The reference queue adds a reference to the Python object that will be removed by the Java layer when the garbage collection deletes the wrapper. This code is almost entirely in the Java library, thus only the portion to support Java native methods appears in the C++ layer. Once started the reference queue is mostly transparent. registerRef is used to bind a Python object live span to a Java object. .. code-block:: cpp void JPReferenceQueue::registerRef(jobject obj, PyObject* hostRef) ``JPProxy`` ++++++++++++ In order to call Python functions from within Java, a Java proxy is used. The majority of the code is in Java. The C++ code holds the Java native portion. The native implement of the proxy call is the only place in with the pattern for reflecting Python exceptions back into Java appears. As all proxies are ties to Python references, this code is strongly tied to the reference queue. ``JPClassLoader`` ++++++++++++++++++ This code is responsible for loading the Java class thunks. As it is difficult to ensure we can access a Java jar from within Python, all Java native code is stored in a binary thunk compiled into the C++ layer as a header. The class loader provides a way to load this embedded jar first by bootstrapping a custom Java classloader and then using that classloader to load the internal jar. The classloader is mostly transparent. It provides one method called findClass which loads a class from the internal jar. .. code-block:: cpp jclass JPClassLoader::findClass(string name) ``JPEncoding`` +++++++++++++++ Java concept of UTF is pretty much out of sync with the rest of the world. Java used 16 bits for its native characters. But this was inadequate for all of the unicode characters, thus longer unicode character had to be encoded in the 16 bit space. Rather the directly providing methods to convert to a standard encoding such as UTF8, Java used UTF16 encoded in 8 bits which they dub Modified-UTF8. ``JPEncoding`` deals with converting this unusual encoding into something that Python can understand. The key method in this module is transcribe with signature .. code-block:: cpp std::string transcribe(const char* in, size_t len, const JPEncoding& sourceEncoding, const JPEncoding& targetEncoding) There are two encodings provided, ``JPEncodingUTF8`` and ``JPEncodingJavaUTF8``. By selecting the source and traget encoding transcribe can convert to or from Java to Python encoding. Incidentally that same modified UTF coding is used in storing symbols in the class files. It seems like a really poor design choice given they have to document this modified UTF in multiple places. As far as I can tell the internal converter only appears on ``java.io.DataInput`` and ``java.io.DataOutput``. Java native code ---------------- At the lowest level of the onion is the native Java layer. Although this layer is most remote from Python, ironically it is the easiest layer to communicate with. As the point of jpype is to communicate with Java, it is possible to directly communicate with the jpype Java internals. These can be imported from the package ``org.jpype``. The code for the Java layer is located in ``native/java``. It is compiled into a jar in the build directory and then converted to a C++ header to be compiled into the ``_jpype`` module. The Java layer currently houses the reference queue, a classloader which can load a Java class from a bytestream source, the proxy code for implementing Java interfaces, and a memory compiler module which allows Python to directly create a class from a string. Tracing --------- Because the relations between the layers can be daunting especially when things go wrong. The CPython and C++ layer have a built in logger. This logger must be enabled with a compiler switch to activate. To active the logger, touch one of the cpp files in the native directory to mark the build as dirty, then compile the ``jpype`` module with: :: python setup.py --enable-tracing develop Once built run a short test program that demonstrates the problem and capture the output of the terminal to a file. This should allow the developer to isolate the fault to specific location where it failed. To use the logger in a function start the ``JP_TRACE_IN(function_name)`` which will open a ``try catch`` block. The JPype tracer can be augmented with the Python tracing module to give a very good picture of both JPype and Python states at the time of the crash. To use the Python tracing, start Python with... :: python -m trace --trace myscript.py Debugging issues ---------------- If the tracing function proves inadequate to identify a problem, we often need to turn to a general purpose tool like gdb or valgrind. The JPype core is not easy to debug. Python can be difficult to properly monitor especially with tools like valgrind due to its memory handling. Java is also challenging to debug. Put them together and you have the mother of all debugging issues. There are a number of complicating factors. Let us start with how to debug with gdb. Gdb runs into two major issues, both tied to the signal handler. First, Java installs its own signal handlers that take over the entire process when a segfault occurs. This tends to cause very poor segfault stacktraces when examining a core file, which often is corrupt after the first user frame. Second, Java installs its signal handlers in such as way that attempting to run under a debugger like gdb will often immediately crash preventing one from catching the segfault before Java catches it. This makes for a catch 22, you can't capture a meaningful non-interactively produced core file, and you can't get an interactive session to work. Fortunately there are solutions to the interactive session issue. By disabling the SIGSEGV handler, we can get past the initial failure and also we can catch the stack before it is altered by the JVM. :: gdb -ex 'handle SIGSEGV nostop noprint pass' python Thus far I have not found any good solutions to prevent the JVM from altering the stack frames when dumping the core. Thus interactive debugging appears to be the best option. There are additional issues that one should be aware of. Open-JDK 1.8 has had a number of problems with the debugger. Starting JPype under gdb may trigger, may trigger the following error. :: gdb.error: No type named nmethod. There are supposed to be fixes for this problem, but none worked for me. Upgrading to Open-JDK 9 appears to fix the problem. Another complexity with debugging memory problems is that Python tends to hide the problem with its allocation pools. Rather than allocating memory when a new object is request, it will often recycle and existing object which was collect earlier. The result is that an object which turns out is still live becomes recycled as a new object with a new type. Thus suddenly a method which was expected to produce some result instead vectors into the new type table, which may or may not send us into segfault land depending on whether the old and new objects have similar memory layouts. This can be partially overcome by forcing Python to use a different memory allocation scheme. This can avoid the recycling which means we are more likely to catch the error, but at the same time means we will be excuting different code paths so we may not reach a similar state. If the core dump is vectoring off into code that just does not make sense it is likely caused by the memory pools. Starting Python 3, it is possible to select the memory allocation policy through an enviroment variable. See the ``PYTHONMALLOC`` setting for details. Future directions ----------------- Although the majority of the code has been reworked for JPype 0.7, there is still further work to be done. Almost all Java constructs can be exercised from within Python, but Java and Python are not static. Thus, we are working on further improvements to the jpype core focusing on making the package faster, more efficient, and easier to maintain. This section will discuss a few of these options. Java based code is much easier to debug as it is possible to swap the thunk code with an external jar. Further, Java has much easier management of resources. Thus pushing a portion of the C++ layer into the Java layer could further reduce the size of the code base. In particular, deciding the order of search for method overloads in C++ attempts to reconstruct the Java overload rules. But these same rules are already available in Java. Further, the C++ layer is designed to make many frequent small calls to Java methods. This is not the preferred method to operate in JNI. It is better to have specialized code in Java which preforms large tasks such as collecting all of the fields needed for a type wrapper and passing it back in a single call, rather than call twenty different general purpose methods. This would also vastly reduce the number of ``jmethods`` that need to be bound in the C++ layer. The world of JVMs is currently in flux. Jpype needs to be able to support other JVMs. In theory, so long a JVM provides a working JNI layer, there is no reason the jpype can't support it. But we need loading routines for these JVMs to be developed if there are differences in getting the JVM launched. There is a project page on github shows what is being developed for the next release. Series 0.6 was usable, but early versions had notable issues with threading and internal memory management concepts had to be redone for stability. Series 0.7 is the first verion after rewrite for simplication and hardening. I consider 0.7 to be at the level of production quality code suitable for most usage though still missing some needed features. Series 0.8 will deal with higher levels of Python/Java integration such as Java class extension and pickle support. Series 0.9 will be dedicated to any additional hardening and edge cases in the core code as we should have complete integration. Assuming everything is completed, we will one day become a real boy and have a 1.0 release. jpype-1.3.0/doc/imports.rst000066400000000000000000000044741405671516700156630ustar00rootroot00000000000000JImport ======= Module for dynamically loading Java Classes using the import system. This is a replacement for the jpype.JPackage("com").fuzzy.Main type syntax. It features better safety as the objects produced are checked for class existence. To use Java imports, import the domains package prior to importing a Java class. This module supports three different styles of importing java classes. 1) Import of the package path ----------------------------- **import ** Importing a series of package creates a path to all classes contained in that package. The root package is added to the global scope. Imported packages are added to the directory of the base module. .. code-block:: python import java mystr = java.lang.String('hello') mylist = java.util.LinkedList() path = java.nio.files.Paths.get() 2) Import of the package path as a module ----------------------------------------- **import as ** A package can be imported as a local variable. This provides access to all Java classes in that package including contained packages. Example: .. code-block:: python import java.nio as nio bb = nio.ByteBuffer() path = nio.file.Path() 3) Import a class from an object -------------------------------- **from import [,\*] [as ]** An individual class can be imported from a java package. This supports inner classes as well. Example: .. code-block:: python # Import one class from java.lang import String mystr = String('hello') # Import multiple classes from java.lang import Number,Integer,Double # Import java inner class java.lang.ProcessBuilder.Redirect from java.lang.ProcessBuilder import Redirect This method can also be used to import a static variable or method from a class. Wildcards import all packages and public classes into the global scope. Import caveats -------------- Keyword naming ~~~~~~~~~~~~~~ Occasionally a java class may contain a python keyword. Python keywords as automatically remapped using trailing underscore. Example:: from org.raise_ import Object => imports "org.raise.Object" Limitations ~~~~~~~~~~~ * Non-static members can be imported but can not be called without an instance. JPype does not provide an easy way to determine which functions objects can be called without an object. jpype-1.3.0/doc/index.rst000066400000000000000000000020151405671516700152620ustar00rootroot00000000000000JPype documentation =================== JPype is a Python module to provide full access to Java from within Python. It allows Python to make use of Java specific libraries, explore and visualize Java structures, develop and test Java libraries, make use of scientific computing, and much more. By enabling the use of Python for rapid prototyping and Java for strong typed production code, JPype provides a powerful environment for engineering and code development. Unlike Jython, JPype does not achieve this by re-implementing Python, but instead by interfacing both virtual machines at the native level. This shared memory based approach achieves good computing performance, while providing the access to the entirety of CPython and Java libraries. Parts of the documentation ========================== .. toctree:: :maxdepth: 2 install userguide quickguide api dbapi2 imports android CHANGELOG develguide Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` jpype-1.3.0/doc/install.rst000066400000000000000000000133531405671516700156300ustar00rootroot00000000000000Installation ============ JPype is available either as a pre-compiled binary for Anaconda, or may be built from source though various methods. Binary Install -------------- JPype can be installed as pre-compiled binary if you are using the `Anaconda `_ Python stack. Binaries are available for Linux, OSX, and windows on conda-forge. 1. Ensure you have installed Anaconda/Miniconda. Instructions can be found `here `__. 2. Install from the conda-forge software channel:: conda install -c conda-forge jpype1 Source Install -------------- Installing from source requires: Python JPype works CPython 3.5 or later. Both the runtime and the development package are required. Java Either the Sun/Oracle JDK/JRE Variant or OpenJDK. JPype source distribution includes a copy of the Java JNI header and precompiled Java code, thus the Java Development Kit (JDK) is not required. JPype has been tested with Java versions from Java 1.7 to Java 13. C++ A C++ compiler which matches the ABI used to build CPython. JDK *(Optional)* JPype contains sections of Java code. These sections are precompiled in the source distribution, but must be built when installing directly from the git repository. Once these requirements have been met, one can use pip to build from either the source distribution or directly from the repository. Specific requirements from different achitectures are listed below_. Build using pip ~~~~~~~~~~~~~~~ JPype may be built and installed with one step using pip. To install the latest JPype, use: :: pip install JPype1 This will install JPype either from source or binary distribution, depending on your operating system and pip version. To install from the current github master use: :: pip install git+https://github.com/jpype-project/jpype.git More details on installing from git can be found at `Pip install `__. The git version does not include a prebuilt jar the JDK is required. Build and install manually ~~~~~~~~~~~~~~~~~~~~~~~~~~ JPype can be built entirely from source. **1. Get the JPype source** The JPype source may be acquired from either `github `__ or from `PyPi `__. **2. Build the source with desired options** Compile JPype using the included ``setup.py`` script: :: python setup.py build The setup script recognizes several arguments. --enable-build-jar Force setup to recreate the jar from scratch. --enable-tracing Build a verison of JPype with full logging to the console. This can be used to diagnose tricky JNI issues. After building, JPype can be tested using the test bench. The test bench requires JDK to build. **3. Test JPype with (optional):** :: python setup.py test **4. Install JPype with:** :: python setup.py install If it fails... ~~~~~~~~~~~~~~ Most failures happen when setup.py is unable to find the JDK home directory which shouble be set in the enviroment variable ``JAVA_HOME``. If this happens, preform the following steps: 1. Identify the location of your systems JDK installation and explicitly passing it to setup.py. :: JAVA_HOME=/usr/lib/java/jdk1.8.0/ python setup.py install 2. If that setup.py still fails please create an Issue `on github `__ and post the relevant logs. .. _below: Platform Specific requirements ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JPype is known to work on Linx, OSX, and Windows. To make it easier to those who have not built CPython modules before here are some helpful tips for different machines. Debian/Ubuntu ::::::::::::: Debian/Ubuntu users will have to install ``g++`` and ``python-dev``. Use: sudo apt-get install g++ python-dev python3-dev Windows ::::::: CPython modules must be built with the same C++ compiler used to build Python. The tools listed below work for Python 3.5 to 3.8. Check with `Python dev guide `_ for the latest instructions. 1. Install your desired version of Python (3.5 or higher), e.g., `Miniconda `_ is a good choice for users not yet familiar with the language 2. For Python 3 series, Install either 2017 or 2019 Visual Studio. `Microsoft Visual Studio 2019 Community Edition `_ is known to work. From the Python developer page: When installing Visual Studio 2019, select the Python development workload and the optional Python native development tools component to obtain all of the necessary build tools. If you do not already have git installed, you can find git for Windows on the Individual components tab of the installer. When building for windows you must use the Visual Studio developer command prompt. Path requirements ----------------- On certain systems such as Windows 2016 Server, the JDK will not load properly despite JPype properly locating the JVM library. The work around for this issue is add the JRE bin directory to the system PATH. Apparently, the shared library requires dependencies which are located in the bin directory. If a JPype fails to load despite having the correct JAVA_HOME and system architecture, it may be this issue. Known Bugs/Limitations ---------------------- - Java classes outside of a package (in the ````) cannot be imported. - Because of lack of JVM support, you cannot shutdown the JVM and then restart it. Nor can you start more than one copy of the JVM. - Mixing 64 bit Python with 32 bit Java and vice versa crashes on import of the jpype module. jpype-1.3.0/doc/java/000077500000000000000000000000001405671516700143445ustar00rootroot00000000000000jpype-1.3.0/doc/java/__init__.py000066400000000000000000000000461405671516700164550ustar00rootroot00000000000000from . import lang from . import util jpype-1.3.0/doc/java/lang.py000066400000000000000000000016521405671516700156430ustar00rootroot00000000000000import jpype class Thread: """ Thread support for Python JPype adds methods to ``java.lang.Thread`` to interact with Python threads. These methods are all classmethods that act on the current Python thread. """ isAttached = jpype._jthread._JThread.isAttached attach = jpype._jthread._JThread.attach attachAsDaemon = jpype._jthread._JThread.attachAsDaemon detach = jpype._jthread._JThread.detach class AutoCloseable: """ Customizer for ``java.lang.AutoCloseable`` and ``java.io.Closeable`` This customizer adds support of the ``with`` operator to all Java classes that implement the Java ``AutoCloseable`` interface. Example: .. code-block:: python from java.nio.files import Files, Paths with Files.newInputStream(Paths.get("foo")) as fd: # operate on the input stream # Input stream closes at the end of the block. """ ... jpype-1.3.0/doc/java/util.py000066400000000000000000000173661405671516700157100ustar00rootroot00000000000000import jpype from typing import Union class Iterable: """ Customized interface for a container which can be iterated. JPype wraps ``java.lang.Iterable`` as the Python iterator interface. """ def __iter__(self): """ Iterate over the members on this collect. """ ... class Collection: """ Customized interface representing a collection of items. JPype wraps ``java.util.Collection`` as a Python collection. """ def __len__(self) -> int: """ Get the length of this collection. Use ``len(collection)`` to find the number of items in this collection. """ ... def __delitem__(self, item): """ Collections do not support remove by index. """ ... def __contains__(self, item) -> bool: """ Check if this collection contains this item. Use ``item in collection`` to check if the item is present. Args: item: is the item to check for. This must be a Java object or an object which can be automatically converted such as a string. Returns: bool: True if the item is in the collection. """ ... class List(Collection): """ Customized container holding items in a specified order. JPype customizes ``java.lang.List`` to be equivalent to a Python list. Java list fulfill the contract for ``collection.abc.MutableSequence``. """ def __getitem__(self, ndx): """ Access an item or set of items. Use ``list[idx]`` to access a single item or ``list[i0:i1]`` to obtain a slice of the list. Slices are views thus changing the view will alter the original list. Slice stepping is not supported for Java lists. """ ... def __setitem__(self, index: Union[int, slice], value): """ Set an item on the list. Use ``list[idx]=value`` to set a value on the list or ``list[i0:i1] = values`` to replace a section of a list with another list of values. """ ... def __delitem__(self, idx: Union[int, slice]): """ Delete an item by index. Use ``del list[idx]`` to remove ont itme from the list or ``del list[i0:i1]`` to remove a section of the list. """ ... def __reversed__(self): """ Obtain an iterator that walks the list in reverse order. Use ``reversed(list)`` to traverse a list backwards. """ ... def index(self, obj) -> int: """ Find the index that an item appears. Args: obj: A Java object or Python object which automatically converts to Java. Returns: int: The index where the item first appears in the list. Raises: ValueError: If the item is not on the list. """ ... def count(self, obj): """ Count the number of times an object appears in a list. Args: obj: A Java object or Python object which automatically converts to Java. Returns: int: The number of times this object appears. """ ... def insert(self, idx: int, obj): """ Insert an object at a specific position. Args: idx: The index to insert the item in front of. obj: The object to insert. Raises: TypeError: If the object cannot be converted to Java. """ ... def append(self, obj): """ Append an object to the list. Args: obj: The object to insert. Raises: TypeError: If the object cannot be converted to Java. """ ... def reverse(self): """ Reverse the order of the list in place. This is equivalent to ``java.util.Collections.reverse(list)``. """ def extend(self, lst): """ Extends a list by adding a set of elements to the end. Args: lst: A Sequence holding items to be appended. Raises: TypeError: If the list to be added cannot be converted to Java. """ ... def pop(self, idx=-1): """ Remove an item from the list. Args: idx (int, optional): Position to remove the item from. If not specified the item is removed from the end of the list. Returns: The item or raises if index is outside of the list. """ ... def __iadd__(self, obj): """ Add an items to the end of the list. Use ``list += obj`` to append one item. This is simply an alias for add. """ ... def __add__(self, obj): """ Combine two lists. Use ``list + seq`` to create a new list with additional members. This is only supported if the list can be cloned. """ ... def remove(self, obj): """ Remove an item from the list by finding the first instance that matches. This overrides the Java method to provide the Python remove. Use ``lst.remove_`` to obtain the Java remove method. Args: obj: Must be a Java object or Python object that can convert to Java automatically. Raises: ValueError: If the item is not present on the list. """ ... class Map: """ Customized container holding pairs of items like a dictionary. JPype customizes ``java.lang.List`` to be equivalent to a Python list. Java maps fulfill the contract for ``collection.abc.Mapping``. """ def __len__(self): """ Get the number of items in this map. Use ``len(map)`` to get the number of items in the map. """ ... def __iter__(self): """ Iterate the keys of the map. """ ... def __delitem__(self, i): """ Remove an item by its key. Raises: TypeError: If the key cannot be converted to Java. """ ... def __getitem__(self, ndx): """ Get a value by its key. Use ``map[key]`` to get the value associate with a key. Raises: KeyError: If the key is not found in the map or the key cannot be converted to Java. """ ... def __setitem__(self, key, value): """ Set a value associated with a key.. Use ``map[key]=value`` to set the value associate with a key. Raises: TypeError: If the key or value cannot be converted to Java. """ ... def items(self): """ Get a list of entries in the map. The map entries are customized to appear as tuples with two items. Maps can traversed as key value pairs using ``map.items()`` """ ... def keys(self) -> list: """ Get a list of keys for this map. Use ``map.keySet()`` to obtain the keys as Java views them. Returns: list: A Python list holding all of the items. """ ... def __contains__(self, item): """ Check if a key is in the map. Use ``item in map`` to verify if the map contains the item. This will return true whether on not the associated value is an object or None. Returns: True is the key is found. """ ... class Set(object): """ Customized Java Sets. Java sets only provide the ability to delete items. """ ... class Iterator: """ Customized Java Iterator. Java iterators act just like Python iterators for the purposed of list comprehensions and foreach loops. """ ... class Enumeration: """ Customized Java enumeration. Enumerations are used rarely in Java, but can be iterated like a Java iterable using Python. """ ... jpype-1.3.0/doc/logo.png000066400000000000000000005326301405671516700151020ustar00rootroot00000000000000PNG  IHDRxsRGBgAMA a pHYsttfxiTXtXML:com.adobe.xmp 72 2 72 <vIDATx^nIv߇/|^0 !4 R QlҲ%Yd{q-jIEY([,/RHJM@ B 09tN/7|;W;Ү]TU9!*******(YQQQQQQq*w PQQQQQq*w PQQQQQq*w PQQQQQq*w PQQQQQq*w PQQQQQq*w PQQQQQq*w PQQQQQq*w PQQQQQq*w PQQQQQq*w PQQQQQq*w PQQQQQq*w PQQQQQq*w PQQQQQq*w PQQQQQq*w PQQQQQq*w PQQQQQq*w PQQQQQq*w PQQQQQq*w PQQQQQq*w PQQQQQq*w PQQQQQq*w PQQQQQq*w PQQQQQq*w PQQQQQq*w PQQQQQq*w PQQQQQq*w PQQQQQq*w PQQQQQq*w PQQQQQq*w PQQQQQq*w PQQQQQq*w PQQQQQq*w PQQQQQq*w PQQq{ THֽWQQ]u {EEmI\ۉi 1\q|-^4~ė^ 1ԟbyЍ*j{!N/kqBܽ։Wbq𩨨 @Emf_GO_q}g?6 ~~[nӉ?xR<,MѓX?^Y] NOK١RhN;hIᙆV;FAbێ3R B{N,~C'baND-VTTAU**npe m&m#aMrRbrөdd.u;sqX={x'chJ74ׯƧ~˗ܵ;RY:kǁBlt(얡˷䇒4V;vܵҏ?ؽę0hPSOŕa 4E[TlރŒ2$ O%e^ڋQ֏;8{:~CŽg/((KO< _1z\jg>啽%SrKJf$Y1` h7+oe`В[Sť30qe`8~?'ZQqg*ov#L/\#٥ܷq!.bD"PGݷh{彈iO{~/F8Sbw?;'N2k|<_@|] e~4[;Gݘtc|ϼ'V珩,H JCppj-`>Xp/C+Ux+ /caP?3Ћ5j~mVP 7z?~lY8w q6F1^h{lX^Cţ8wx~wcՍ&L{s//|\\ڏQtOR+-ŋIO+=̾-sڋû>%0- ?`q߱wZ @E[O|ZIqL훢[7nv;@f19Տ _ߊݒ Mc:Нb҉aLXYz VN zJ+B'vqṍWs.SЛCJ1F+e S^E+dtFv_iZcJ0oI PpSM[`n lK ?c#;ʐSQQzB?fȶoG=L釻ݚ Mx G-hKxO{1]Pߋ6^$ snt{ݘHY~a'O~f 7+;Vѥ\yjyl%ȕ6B>v=]~e%Ϭ o.k00U/=)/t(wETToĀ]L cdXX[B;囄.3bIn-hf׌Kꣳ Wz; &RbomYyp,wEk8@?zKC ߖfٻ%ɻwd؏)v%`Q3ygcS_hwTfɊ<\U+RX(En*c[4.Acկk& 7W/lGETT݋W#!$@;*GWۛ0'Y/@. Xkv0F @7:Wc2PʃQ&Xo"@z;ϻ)t[E '_;0Qz=~οNz;'KRDXBg9`VUyN8~C~'^s|姯WMNijWBSEldY[uf<ۯf%-->XRb_l;$֖m{#WL}i&EpVx@H]ޏcE) K^W>J&((!H!P`< ~񨨸3Q77wc{,KB\Tni.{v3{cG 7Y Jo (A#7;X_}1݇hr<LA,cOh4AIX `Ň"7oME?i[o3tU>M][2GM"Оe&3 nLUT{VTTIZhI`I|b= &n E{}KF/ fDbaٟln;4]+bt/Y)BZ4Vx? =yn hߒ%~~EؙB + :DŽ]Jp*cKMRNe?3)+Ei9d蘢T 偺t(F'ًPQqnXQQ&aH"Ȑ)dW_g&@鏐޴:gh.Ҍh>=7ORlk=KO$79>L_ \&PTw%L %2^;їT'%7f?щyϿGQ$+0E軜{CaohcE[ Њ㬌TT @Eśn3Z |J_X! `ExA"+}LhOv#2Sd?OTb+;"hoa~m"D*T8pEGQp)_ɫ<~u1u0P])Ra:w0p)?~ݳ^0 lk&-g03/Ky@vzrs|#`*? XO!~y/k0{|_%#Dž?;xv1^:8g?^s0r Й@#o0p:bz:lJ!7RLNH@v^$Q"?{ӣFU**dػx@ZHalPh}# (hwcir" d%m="O|:ĕ<'a-շ{y?Ƽ Wxߎ&|+_7BAfA2, B \nG |^?H$m}ksCGE 7xXǤj$.ӻT4} uouVܐ?}9g3[ʖ$\œ~B4 #<&Nb~f";o;X$ȾN^y/h[.L纲+2~φ?{; g3ܨ| ~mHzhP%%*~@{R**hTMƱn|1fw=OB+geƮfv#߈/W)|?q࿋{/;R*B3uo%P%їڋGc+#A>"sb&3S>{$')S$I[_A<4+ sAx~/wcw(EejPI9)u%7d 8W>p? VT @E[T˓T )T R 3b$&W[c UW'NX<=V\/"AcfDѐ'`%'ky~*E{mk9*c-.II櫂Y1@`AIIC,PJ8(fo<$P e?xr C 1T4ćuo'GNcVT @E[=qϱ߳=sv|@ǯRĹxvė7Epw}q؋1~񒤫‘H" -vY%mW|~̧zYt/ߋȫ,( .GЫwվ%{ &2\\ i]/V L3/Nnrg:/b ÞIQP@T?0ǜLEEEU**8މ1>Jfw5 QɆ8-Lď<8#c1xZ9݃K[P?[LIt3 S7"9E6cEUc܃NLѹQ잝 /^C4!Yg$3v4cF%͸W:)_4ε❊_鹱:8`8Ywwo?R***TTEُ<kNKpIdIIpJ brs=)q~w#V+{-D|~6&_PL63j#5w'K2|W0By`_Q ҬLy#e:mq?/-xoqCx_x`3`KV^V#v{6{ꪢbTT_ŒfDbs{|'w4Spf.gnWS܌, l({~sؗ0?R@l |^P*GꓲG:]D)[0)D4ӝIݿ8݉O/˚bskuY[_>k~N&xO?(?$άUx })*_6ݑlt?`?ߓ79t؊$opG\rF / y u"Z [uC?3yg@ !px2W*[ ]9|?JB)_8wy/mE[[W>X1@:ScmY***nBo1O/Nh?L6ejz^7OH1B{g{/7ȧk@q}]^~/>eV29S|hA[T(8Ca|׷&orb:`,?o,Y4 fkQ~ezy FŒϖqXv`n'p[^-N}H,?kW/_;,Y #}g(x6Č Kz񙲔AuKrT^GzP@g9ʛom[ybוB14E^h ^W蓭X0= ޠRg#9<+**^/ğ~<s+ojӷ|_9jߎ^_Tg {ߌNFkYBRq;;u+ JZz8Xցב{GhcQxXkS!~('$鍊ڽODg>pO b{;_~v/:?~>{PPXy V2XY`5%fH;*.ş5KJ6xS(AI@Vބ7jWb:u3jf̮q #t?q1f -&75^~䱭u yBKxPx {U X-ڕX~ߎILW&#0gTsy!ʹȃ򬨨f @Eȿ|!O|5V)7;IT(3 P(q} b2S MxE#H B!RO<%e}ˆ#b "Se( _1az2Dӊ3뱽3DgI-!>RF9eL&~d***)PQqbw;+XK2kN޼#afSV8uҟN J"}/8nE!"|INNcW #`I&9lٳmO?o+ B#?W'@i P&$͟.~E9 I] Q!H*#J J@=~z1?6Q?0X,7w/Kh^`G#)} Gd+rq웲r?&x!=|6f1f{%B|Z(gdӄp'?^D UƶTIO Rz^!:(|<3KKXҿۅzREEws-9g%YВ&p "`-h (AeTB ȄVx/:(߂}Vp߸xo[ _x*v$Ė{~**T6?'b+aʌ[^B<"XBY683 {2{GF+΁=]fǬ_\nڄ-㇄'_.d>rs_夣~gC&{3{P @[zou5@SDq)NGg4~k0P@gg7F@'_ SvXmGJ?&V"Ϯ}LxXtF9HA^eF `dۤ:1I6)lE+ u|[4YP^FZ(} >[QQ*oxi'._{<>J82c ]q-~#<# h{cJBNӅB'SIҧt*e~x"al*T\?  Jf~+p8'>?[QQ*o|K-h?v'O^3B–C=g S!+ʀEx׿-R="4䙢iC<& `lvd3y`?#.2S鏥L$'>PE;㘔/E{ԎA3i7tbldYQض[?n,xs&@B.Xhu?=&l3(~,Cy2ޟ(W*_?JXEEwTT {%sF'%5KG#HYGxZ5oSGX;* ':uETTݯ^wbZJ@])+/J ])|8HuCjV+.`w"E@wo7$xYG:h:f\7[<=8SvvE!?--ؽ1K(>P}οBU**ns<}i+s|OS²])΂1\>;,(9ۖ`?B2ږޗ;LPFHkX{^)BC1gGxi΂_柭.*R287񡇏KG**PT6 1\3~~nGJ뢄 KH %d̶yƾ-!{ A?"f¹  tS0> kyo l!9@3ȧ3'@EETTX`#8~ׂQXhJ|tP6|.hc /BÐy乔)~x@pA磽zb3WXtw?;Ǎ/{H_t(@oUNb?dO7_pRQQ*16&`.si8s2dLwboE!ď ;lBD7^،exsQ_${] `f@)-ЕAK9٥ `.?hV<aIu@ccz =Q|@^FihRc*NF;"|@3~ka;1>.kEEś )#O^;I0w8|b")`(czwD؇cVF!]>\tn9@>‰ifLy m)<] Ccw1|)R>G{ 7 ߜ387[# u4oz::jG{ؒ_DButR]\;;ēŞ&yk/ߟFnOBY,i"zsg%1D=Wc8`鞏%\H/Q~xߴS`ՠJ>K[g"MȾ=?G3o5&cbu(ǚf񻓘uc:ht5E{}/F_;{>/z%A,xp |y `$'!.鎄tJtE3ѓbaquRP$ؙ-7m[qY\::x+Qobi}?z߿û1]ЗI5:|W~mEX|"Owg_*1"|Sb4_t3~ ^6_C!gL٣ {߉q?_B ;/Ĝ^+Fѹ6|ok9At/ycݖB =|z[б=o t7`IB{Y&wF';[k&;hZb?_4WxeN?,hEE[TTfG7sB—,.t5Ŕm{a/ؙP¾/b'߳"q_ݷg=^-& 澄`^~A|O DQNHЯ_ݚ_=B]Et$B'zRR:ʛȽBa_5>.gEE[TTfx*xA{ѻka=Gg}~w, S چ˝8X1"E|tt7׎b/:2ۼg>R^gi_~@{2%yo))l@An g> PObt7h> W,D~L%y5F/EHзZѹ_k8 Ii8ޏ$K`,k4ivUz})]f FD)@޾hQz( /rёRq bv?P)iEE[TTF/oE^ݙDoCB|?Ms9-x^-۟sѹ③o f@ \+&s%p>U a~bN)suHQh/AϋXp:]qJy=P_H:?Ͻ Is;`Nq^D[䬔%pc?&w͋H!Dx3 hK8t0p A>=>H-T4!|4.% LY/$ )' 1I>_Qq;* 6Sz)rЏ R(D?>=~ ?X/)Û[YGRҊUMRllMN}޴r#H폀n`y?nhJ;@6 ͽ{:V&䔝 L4)Jhm'  ߳%?x< lTx7وc1K"mPQQq~~Vk{Lr.@^ۺpNL$-0 [ll ËV 4_$ e[[Yg}>Ž?7KoebƴՉaLU!ţMc_W**n7T6A|+J~>/;\^/mK.gzۗR?wAaz2D%1o!OmEhQP@ٽ(^9-) R4z1^xI[{@;̀#3:U梴5nObeTTT6 @Em_ⅸ;rљ9)cWoēнY9:J ?c_XP{eEmkE@,}y#9KV $(o(j(g$E;xXp~)FQl$^Y%}:}ox۠FrW{6NO~Q***n7T-^'?R 4fCzjf jړp֟gYG!`i1xj;<&"oNbtv!@!.c؏6k6S m[1nA$M7n "OyO"xP dx,P]QŕWtSn^;<>Pfޕ?o;sOn>>om|?A}e/łnt$;7HKS1Y-ĀD-Q Om(e@;c0O***n7T-'f_WN';,K+Y_ُf|'mE l)s_ݰrݛD7J`[ )(r"!fA<7fmr~ɼ,۟'ʁeKan'忊Ux -AO̬,xm+k{R|]~mE0>} %0a= i Y)@`#fH>/^ْ2Ž< [WEm.hX%P>ؿW+ݽ$>qשQ7^~Gw#t5}KO%xN½#m6do@zπ¸o/~\P$: i>OhGIYA`/eaLK\\L)4RF4? =4]ŸR|sba,3> N]sٹTw'!{HK(#6'~J~{^vn1(.|V b P*xx!Dt z6đEw#w$ GEE[TTE|u/~Oc'?nV:iSǞGXWKN}0q%R'ڱЍf< )Q@ D_PD9xھ"DloLʵQL{{co*e Ux/l>1RwvwN[}ϱN̷8׉ oOAٴw\8@x*o 43o0x/` Xd$3Í0v$L :R[\`N caeEzXXY;AP"***^OT t{7$Ʊy=&aLwbwS~v=ę;7!O:*&2 (l^,؋h iaOb*G˫斁IOK(6c>K, _$N&eI(5R"gŠ'O@EgˊoTT|nݐPߍk1ǞͽnoX¾-mD*oC xǁO!B34^6Iz4jӈtjie_|Y/$ąIMB0Tw,nr3$uv,ݢgqUxM%ܯKhg#f{{] i@;Y4"^~!*A]GA_H7Pdo;vo\Ҕpзx`n௣c%@+{CNR*Jl 8"qIf7}F%Ke,9;& .kLS/I˞#y*x0zfҸِgSIYM(HGiF{ 96#H<0Ne `2Rp2'uH9/[P%aՋވ{+p'yoޖ +lg i`6S5tE(hD4¯!✰ٌAz)ˌH>"osLW +8Whl5TB[>np>|~4< iZ.iOg]O**ɖq j{CaG=s(bjDNʙrl,7#VTE @mil]z) ףF {xޯk^egd9k[E+-2) $Vߠv"2T6oa73dq5L>,D:La,h8&Iy֔)(s֍"sdMڠ5Jz\qBҘΟ1=2sm,>%8&Xg0-*N_Yջ=+ oZxsP[_K-w4K {~֋I`_RuS,3CPRpn&x'40AT)pREMFO_ꦔgDB3& ] §,gM]MXw٧-N2KFIdEЩX9L/1 7nB^`pc`CKҹ ͬX.+xKKqb.)<** T-pjNf4Y{y^lz6cyQAde@ƀ{$d3q sWzPd::[lD'ym|%;^Zq̙|ʌ3?+a&x: QhPGfd@Sdɕ(,= /Wj,ud:9(LGp /30QCm[ qG<awTan]k=矍h,7o{GFijf?u C.B<C ̯aȥ_帘Gbbq W ԩ5NGٖ, ej Xqcr1**Pמ"=]y89zH+ȁQ7;mMFK`1d<T⶿ !P5 O5 MH qT޿eJz=͛!\ӆߌ"٘%Ha@&{d[ٳa-iࠂ'r"SMM!:+G Υ-gz<f<סF5{=!i+܍#nl;':Pm{Z5!"> 3ӓbM7rbrU*^U1Yk~MB2KvːuT5b4lexxhp+FC&~MiwK<[ 3yik&d^Y+"4n># qyN'v֡f~3ۡϡkRh, 8`I+*XYM G_qDg P =eÝܹ0_"^2Bcc{milfelEr?{(:5z_ /cdABp |8 xoă!C(~ YH>M:4QX1f-x.xy/EGA60+JHӟ8N8-.)SfMt{T3k;P'MnfFM&ĵOt78tfv]rouyd=8C ;U}f_No.kdЖeVY8,t.N,ӍfpG1!]}|GLm/;^l|l_A4T7~e y$#MΪə7Vbta&h#W:ˉlZđa}8~oقh^o!:lh}w;'a՝_i"ݚѧ#;;r;p"pȯɋL 8]*;8K|d(2p ~X#!7 N[Ƒ(:~$nZ]y94Ŵbt]Z. &#g(a}_=1>Zx'*q7n:9di:lF<4L=кGi?\G3 LjVCC ^vG@;^v47 $V>Ó4.<0 L|b<I KXs4ڋd({;J'['(_O 'w^[Wdyv5MG|j_cC.*` "Jnw^>ֆh_?U"Mf[ Γ"M>l&S*80:4O$OmZ+^iPp0|HK+j\\_^I .T~tPE@,@~-xO}Ͱ;UxM_O}!n0$":vt]hAe4iL,W7F %}hᜎ2ЂC_k7Vl9hfr /V09`K GҩpDs3~tx<:umϋ^RxN؝8,]"gsQ<:n7-ز2Zf";t Ȱ+ﺳb@cS-Y6rfZ0)-EW8mJm!TZ=)-`ny_3q;^f¾e{iim%MsGuApgѳBl-']+^4C )4q7~ koI^%}+LǬ =ĩHᝂTO|1v77%ŃIq3O(aqW9>.߾'Wq/2hlISlLyM 3jA|A[gfm]"x56m=v5cYp2M$7f<%SQʸ:.(١g!LԀ홮œ@%#3DxY,KSvQؗ?a&9`-mw[2T(L}K^}:p{22n# 8ys{Gn1c0XT[rK?> ,$]YK:93\ ^і`%|UIP:vZoԤe*XTd#ܳkH^P]Ln!M,.ljGkg)!߫ @ /~-.~<k@b Y 0L@:֠0J O, z Sɏg?g!,eKz 0ELa)]3C1ݗP2cz ס/rmf;C+xgh&79 Iu.:څ",gbr O:`k! 8TD /0mS@/V\ 9_+ͭtc Eaib!?)D",qRYdtƿɋ}pa8Tf&4S0 @Cݤ):Vd2"P.WlM7j">{>kp^CU*SO|^fe` x\dx`3L B'>-K>n;A'ۑ z 4s/bff5{;f1QP(rN7$ ȴo1rVb M`d'ŬBXXR顰4ʄLzkn\ndr'O#iv4-gոf 7p|KApY fV,>rL~171_Y{ x㺓@u? m7WLX( +'a|zc kLKX\&4T“xoz{Ua;{sp2!%5Y/; -`|aaܶh?aHf;FNO;}2n^)Pfo<ަwѳ лY*9C2O w&d(F^C * Cq(Mbx+We0Ϛi*(eN*e.4 sIkBt\b˰Op7m`6T5J tSN$]%aG|mAIyCAše+})@q Xw%gDm3\ي잙;@^M4L)9d~"!}}'.F[n|:8y6W)GRO?|*w 2FOu2x /?* r%rpbo30<yA(@\h%MMhAL*> f"(%vnĞb;#2FG@|ׅ":+^`1U`@^{,nD-p(6~Mf Q;K80%[ o?ck*ousm˴d-Xhfl\@hBRZ݄Ƈbu1N}I'O(w~~鄋4iW .t~Za~q51G_[,`[ J `'v⡦ 4,&x:7~6A"ô2e4~K^pŽStJvznzkIdDѤc1ӆVg^[ vvVqL8L4v\Vo_!=[t- ܳj2N9 _ʝ$ 1 ^n`CZn qo+i|}:l ^n{*ͥgWVg.$B>rf( @``23`ŧɁɁM1`q4~=vv51 I{+щy|61tNUƋ` &yLv]¬pY0BzjgBXyþ)Zc#\wIZW#qoK 2ܙ2bf-Hfp/G첎ٹ\9B +qAâSMMB6,%NAv[EZ¢ջbqD,򵟸eu; __#`wCpF uӁ): i㴇@ZnG1\ `TvӍm8~퍷pO/+ 6gūORl]|v[` Bو,h4aU,b P1Êg?f  |X3 f2Q8xN"kn*Jp^ӉA_C#P?t`FoٺNn~J1K9 L%k47* nׅ[ Lz:/7 4rbKXơ,Fs=S:Eh4ǰP'H·]%^x*ЮpHq'jD2 MH:^by5: iRJ)d$ aG,JԊd8@T/Q*+(](2X];K(dUMyb9L43.Ξ3𗡀|"AmZM ͓<T(H t>.o+co*!x^ɮ+و,0Njd`Q@Θ:|!P1B8 `~ 2f3yپۚm_ 'gW,p@;m Pxș+fVWɣbCD ~!p]i7qIʛ[:sD;V=cG6µJlsuoZ̭$^Tݹ߸G^<(nts1qrW6b )nyKm]V,H)ۏcb[Z+V+|rN}/  luqe=[?+ġ&݄mZ>!L*93G`'|pꔔIk,Fq4e)v$=Ơ!fpheL'V~SZR(gBӿa- =nOEЗ - :yx@J/| '>=\xPK *nGT{qDOO [cb Ϙx=a qhrT:;\LY9##~% {[WbgJlKx&!,K7rAVݙyg1;$};XF/̇4[0Upnl qL~PWbާk65d_Z,>Ozi˳XZcK6]k1`;XXW+g`?+O}=N>˓ Xod]_S;n߈ћ[˱|ظt\qRS}Hͦ[u JFG@תn6-RM1OmWUzĝTvNf_Ji=Lv(>ȼ7[@vC#\;VTKGwӉAl w.~+=08Mӏy7dnDKsQw+{_蟴AU܈'Dg̠_ t\gX0[ÆxF/ davXn\āB Ke[2}; Sp:ʗ9{Kd=lwÞAqKxCPXW.djSL*M89OK&zi\0w2zRD/7.s˚Kbos=y8ƚZÏ:1rl^^3~׋:‰RwwaODZ{/74pLeJؿkw=z޸w\lzU^VL jҬPi"̊jjR^r'wR+} ( ]khJ*Xss8 &4Y>eR ʴS)d#ґ\V2iz q2v.B^.ԚO}O򡕵qăj(g'MjSWU'kE!w4>_.^Yn@pYty'OxS{=P)6?/|עP>N/w:L67&6A\ 4M1 uv cs㢎 9Z+?9bk4Sx3vnx M~> ijC[߀3ES r yfb˲r2Y$r`T)!vk{$J{j6zK^Y.t܋h{'xDB;/?c1)W/ok(l7R4֯mDZџhw/zK^\y W]sk1ڊ+<e)ʋ"nSP^uzٸB,;0zf{Bh]dKKP7:*~) 27vV \*AEՃ|#M/-wsMKٸ@L:ꇎҤg9M?jUxs_s_?uZzk ;i:,tA#@5d](ub̆3Gom]~_^G H‘Vy)|ΈAnz! HR-yxVYx$a_L?i{o z:i 3.a;+AC@L1ηc[u_X {$5۽~碻w҄" ϻN>nmmǍkvPQ\zy=zN8u:?{x/HJk,bڋϐXq9 {c2˹AP3`[|,B2!݉b՘?jhgm~~R{RTΞ ]l>%f)DBBJ\G}1'7f4'N$"[J(k~^oNqD!b/n("i@ lt)m^|~QoYp *̉2{ ~Uu ?qܳћ/>]V S)ȥ֟ ;/~HD_Η76H _-2fG: L9Kd-d#OSG\N{3{!Z9GEI`k`̥2r1KrK*ē2Xj+i{ [M~[2xw㳤xk;B,8,~w%Hg@,q R57Ь۶^8$)A_Y /Vbgˈǵ\0k +ZɗV?2ё_"9[ J.u4;H🋍ѓ4;wrK͸΃*7?C R/߳nHGҀ6]SM`n?RJm(0qg54֜Mm<Ҵ5y0oӀ%ay?\?p#mR4CSr@yxI> B/Y`/dr6eb}q@Qf*o\oic_XϗA1@d|9 eGzn33noǵk͌@ H3lC6'200LJySx"CqȻS "wvbG3=a<*4O"it䧐K&Qoalin:X Gn^YR zCOtL-}ol]8sFw9I`+bR&/dv<_0s0N^ζ_^q>w{X9sol_}Yٷbq3zsJo_9X<Q\nYn)Ʋ??"I\GhXK|N[f9o^@! zR, eP6Yw;4[Ɨݪ;!J8k:$ _jnqx,5WeW-F24 <8!b8́\ $,Gؠu] xPn8߉7F~`!K|4ھx0=p8 ,$ōJoq 83MkL& KEȳ b3!Dٸ |)n Z1KΞ0F܂P3wN4?Bl/'W]:_n6M('iBo<>JTuqb|!?Dz}K_|l|!Nؾ_Գw=^|\[vF;;ۻCɼ~m3NXvy7cnd-Xҟ_+2c~G ƕغvQtb0[/wxo ܴ ӭQqW HK|.e" Qj +x6;s͙]\MFAĜEk+q+$+R ϙmg>ӓ(ؗgBQb3i3y472_]Y9ǏCvI:Dd (Чr/ ~dnÞTY m+/se KՐ<ؘQ 8qW:tAf/Ypo'\f @.jĥ[02H3C+i;VAt@KEfvq\H#ܤ%_\aϭN=˟߸9ggqje9Z*07y3gc>מyZa#)IX羸S:3/8Ul+i"^l~ڲo`a-n\_>X\=k񣞤XXWײ?Bؒ/'7'Jt*A% t*mE WVUX*^1}&DZxx`~%yOl$3Z6=b/z>seAUncLwo5)l{,Ei zaԏlmt: -1y +˰tK= ?k;ɻW`# fǹ Ov3ݖ:n? }) ^頬0iAd6uìYIڸd^ЖăW֠(>^q@3ջ|\9 U /yEp? q;3r}a_Lrn؈܉ igr#TKV [F~UxCp[޵n^ ߍyњǴS/6ڢN/zz^^D$&nqM桿϶ ϙO lL{H'3y6;kB0?Ղ`Cx9Oѯ^"ec_G)t-Pv+Vжbr P⺏j5)e*@}g8 Zƀ4 i~g;&;'p_[Svkfa 2QgѭfZ{ ~߂Ϊ$?L>LUU?/4lJb7K?VlmH#Mp r ŇGHJ[`JM;V!\"[0 z&/QL utR P^0uEVQ$QK/JȮDZ͋b,˯~K1E ה 6ַcĪ4vwH)_[.鶮ۈ.WaT&TOI3pDOXTYUE)2j:a@c)sKpդ?< !4GVF,1Y۝&~AhfϐtSꬌeyp5"s }:o>ŭ V6*+yvSva&A[rej̔hԟ}cRO&3|O?r`iO:̆imt'y+{eJ HHf^--1#U(BI!YS^o^X- Ʃȡ =KR|*HT6hF]GoTTx"er8}׻ś@eQcʇH}@yS[4[N_$>o\9XxCP _V Y=(R,]:9K9G_1._zBZ8K!j!",Z X J^fѡSϯa#77cckQ2_Ȓ_ 7B~-:[0}70 Jޗ'cR,)ˌ'f&JDQ(PRf|]dC+vҁ/o2<{k/<˧^T'1|ܷ6^~{D?Y&)tW\3wV;iŎiy)DZ!~]1<,'ݩ2lU(_IT82pǬ'Q4ى5)1]W,#uc؊w1˕Ҧ9nrO&WnyMIgY`Te͹|aU刽)~M?JEtd:z$,d43> &|XY[2Ksf$̻PKLzq3(,Mf}q? R'26>(K 1eNN{9%YoğM7Uux5G'Rl&7v錀_,/C9sxG7= g< WS%="خ-!uYcoi}csO<yq*APtV4($ yHx0?͖A$0yFys愩*9.$y 8ixTvb3XfIf%BAeCS生1N-t޲_;_`l]G~ ݚRq+%~~8ۅٔ &LREޔ eu4msXFHϸ5Wu7gc0K!?iPR0-qୃ'YF[l"F13td>s1sFL P28b)ɟo~i~>V2Or g]u!:T'/5{٩qZkO<Dž)34շ#Ӹå̯ |=ܬt5)Pg/(Y>9|ݤ ,-4kd>p2JA}Y'JԾO?k+Zцu[h)3zV;ˍKCRa,'"B68/گz . f zŲ$aɎrkq/hV3B|YNN(𗳧vK8k뱱Mf430 5mlؗef3#|@c^~I))y"nC_0hc{98ʃ@TP0&Rf,U oѲ2x/.~VVOާNb#ɾgJmЇQ?cvܿ@Qt{)%uV쏦7RD=ũ<܎J6?a:TޚԵb;Wih8R? ^-B:e5mǷPpYᕬ"؝g$8 VXEBH3M;usy R/u!IpJ:GCG{&x#0TL,XZQ)5mͽ,pg;_GUn{*.|S( ]dNCbi@}E!c=/sECLnq"9$'wOxbsGDPeYY&"oήBnSWUJ#G||_#,86\fL~JzqxaahXvv*64jңQ祿G'T_`my_6$Y MK(TnVJԿ[R~9F$C<(DJJt|Z Ms9)wbGxQ>ku,r6 输t%|T|v>Ep'wntpNu :!d?>{ucg9ZNgqWxr_‡{󭸎5+!l T(+N0AVIfnrcr4ˢHbuIHGn޳Orfˬ f`A;i:4(.8-Gg'#x>ziٸf kb]%?KMY^juLM;ƒ=Aoz)t9\E+܃B@l~#DWs<ReO9DB/=!rjꯋڎIaqod&xW|t#/0hb\y&_KP;|'IL+ ܼ^^_f̀ΫO-g~]"xӅ4}+s_!?"e Ϳݢc"Q){ 3j>3pz<`FhրD Qh4^l<.1 Ve8?UyqA,vUnG $/4%~J+Js^;>˸f ƒ޾9Kd\i~O̕gފ'LȪ)\*\*sRr+>}N)Qj$a1ѱxV7rF@կ~( n/Ne\IaGЁŒRFu5~M&cr mcʚvڔFS?kIX^૑ o(ǵ W4ؽ/@1b75y]?ģSf(V0T&+9C ^kdvIU mFkuz~.500vbOw~n Y |(✄ȸGu7?`,.TϠ7HT3/ʎpfyn{~s¹+_wu-xD}cWgQyG?CC{ sG_r;2FD.Nے44=#S<6ܸ dUivi-~咍dC@}Cp %݅e&{)B?૔?5o壨6RsQWp⢌o(G} ɧMsk 4KˋVP P6Ae#.' 6,PfP}䓼#"5?°yo{MU ux3Jw}. x,ҁ%yC*`8W6ؼ2[țGrǔ~Hzp\]JzX4\myD"@t f*e`[x74Qs T":E)k[Mi<)Ǻ0YgFRi.-v*to'6U ܜHyZ*o'@!bOv:Ro `yq\RP^#M_G_T*ܔ_8TpNMyu`7vԮi>GqKi(,W3+γtX(*ܷDKݎW.Zd~~H+{k>_O<ʿtVJ ,u~tR6/ ..`+Dƨl%+\?Şu4Q{G~2CUn\}+q ~!%`hinυrs9#`| -fH䁈 @W7 wJ{A2sZQ>bo> 3/ L)6DB?|61Lh2a3fn'J*C~׃j(g Mנ..RABȥ@ngrunR B7Βxh Jloǵvzq= 9գ֠.㼇!K=#@-9>ґ w^+3M7UĠ4PZdO|h|@_+6̂F7+|s^#A?3 wFaN^<"`cpoGBGȀDGݷǠw+}F@sj=Йʁ|ʮȩ$_f GAY VKPf~WE/ϽS r-s&㸷w)ozk?DZn?NZZD:&Ԭ,l&ڰO~xODASu\+q(sREECq1F\f F|Q2Oy3Fq풺jyf趌[f#Ht4E6ܲb:وgesw t)V;Vb%!7ؼq-n\z[IM^Ny&h1IOX'xhl}QXtZ ym0Fw9hGC[^<្p+^?xKU(C?靳 |/#3$:Fl쎢hėE_.l/䀟 <1N~d,pOL~7m?xU6!{)Xlʓb =iqtؠ)he1Jr(:qT7QFP%>Jw8x*E[$')L&!XAOc*N^O{nW64 /6-,s(k26W h:ru 7}f7v-w+o꺴5ez4u x⥗/.zR(K(u/=9\ DY]B)~,e0Fu6?3)ʬr{7-=xJ(6((":Wolƥk׭ţ8[ΊЗ^r 8zGnS^HO|ށͽU`P` v;wqwdt=V8f&AS/B}#slج{J;MFr.+a@>҃@ث+MC#0MQ?< y̥L|A/;VV2eٹ)TD ki'9H,v3''‚՜fNĎ +fӉ7\n/fݲ=!_uRDԇ `#cf\׀:?74-A!ӱ:ͫJ`v*y7],GUh.cF: VaS++i!Oie_$(2-XٷBN"~F$5Bյ欮@?a`EQں+4|`p  l 7ҳF}5eA,l:xTXy9?!EnyH*kLsY(>cqͳEUn<[?^ӌJBWG:eEg^@K98pAolŹWE }o o;(AOa`-ǍA!-9MG>͍ Z0O{"Gr_Ƽ*-ű,7>k) B?u-څ.Ƃ񂮏JasINtЎئRGA BXzeQx@\ [4)VGz,.M͵ ZȀs%̞: cюw闘*G$ 3ff>QpI{6>l^)^}W,I:ڥS;w/?6#Ҳ)5Fjc<ج6T2NnPO{V?>#)h[^0 Twdw7_е«}]+9hHM;i n?磭vUMp˿W}ʂ 0={&KYBč }70x0`1P32ㅋcS3&^S250L<7WawDEk+lϘYUaz: ]˝x',mG@!g\1H:o.LMzQ>onahqӡ[HE6]s M ru3ߋV^8+1b(tuֵgɠ-={'?༑!E޲[PP8CL̬Y Pj#bɳ)a3_K %Fm7!<1r8;jY2H7nCPv|$?&%Ï"@<ȁ"ܾ-AD]? aNePVV֎K5Avv.6o X;yʕیYuN9djxy|'Vdo K1Lr~ ~ ͇ +˚pܗ~#n\uOo)0#;~1|tt6i5Ms/[yoЈ %WVvEUL6Q܍, a` )ҀLǝL‚i!M.yK W}Pz@MF'ɦ?662zfaaܗ:,8Y3?86ĄG(l5oUO< ק8m2۝7zvsXJ«1\6u2I^h_Vu _oRJjCAqZ:> qb㗔wC}hg{32HV^LC?=RʃBI2^mMn* vO=ň%45홂LEaO 0՗[EU % kP}cqoS|=F*dJŤ^=C!TךkuSj5U`0YSo HѦJX–eSkӘ)RB[C61p{(FRS30APl',W;!2&Rx_i/iTi7(/ pmR+/ϸl۬xULtUO c61uAo 4c+eZt{W_p v̯PB pg]eAW✎\Ƃ[;: ޤA\MStu RIqg\2QFn,u֡jfNY8xr=DAYHYb?d;_?_on|>D{,̱wRߙ뱼z|ֆ}(] ,i?ˤ |+>oGDQK$aE޿J~|ty( Im[GwTcC/J__{gcG3~ޒK\I:ŗzIlWL!p$c-JEe% ߦ 5|oK Аi4p6;Ҡ țݳ.96n:  fF_䉠nqdъ6eX$%AyDr/QXFcUo} 4 :M} \4C&^ݜ h̀7&#lxáARgIBYL3lD:ScAPsXڌk xEv<. ̳=,m4ua`Q|ga"M}nFqEڹu h7I\gn3ox%1IQo|2.Tyha?뼷q.捸Wb3.bکؙzXZ"㱄8%W"u.cvxQRB7e+S Zlś7:1fDKg_mk7˟ww9]A`v+ efG}n:#sxҠ9s&GpZu)nk+WtL05|;)ń~B@Ǐ͑}] sЋ/=o0$MMJe(Yh12`s\_^| NFoq_O-/؝o_`畺DrFyS=duC錓it. t HI\$O%$dE*#񁵯bIԢ{?~:8ozlKyd%9.{;qL?Y-Q;̭7I^k+Rdp sn{H\ORqU \zq=#{ 8˰?& Ї,QSԲ}F( uI?,,ґ5˿qƔ nmMؠׂ*%c5?75gn0`XƜ`; ;Kg/?텦-V48X=ήb-.ōx z>6;;CE$/ "?O,+ee et9젤.R;eѾy+32݊ )%3qGyk|)vwb5ٛۨ蛺MSHA fR@?[Z2rҗ^'c8e#Oe2iv{k A:Cup@ 4APYe5@vBDC\bmf=h<\"`eA}r %l7>6k?w?0K?؋?]KrUU=Xz9_"9=6'@u)fV!;,k;=7f5?n+ʩ,KN&ݬLBiT;3hL8TJC9U9'{³~I,J);< 鈮RK\NWn(VV*_Dk6@g+&8렭 /`masZ]3/^x {ǚe =#a"G`Jlx?P)y/{ CЏf|CzIVD X1!WQ_9\|X@F;[[p @ O#{氫T?.jֿ|ݷ; _x:Ot㏿-~xK1Xda`l"9XLR+ 2ؤȣ:+͊-6KU< #~gSf\!`^(@,XB~ Efnq}gbwc!6~c_R%=jE݋Rp.*Ϋ46㹧Eߪ+WuUu3 le,p8a?1DÅ \|`80cglalp:-#ےlI(LN==+Nu֮]5=~^Jߛҹ3jݠ:& 1Υ<ӾiEč_\' ]r9/Є}/#|ڳbRh[RF#*f:A8|fsyҸOhjFs'ßO ͟(χ~cHf8'[nXW>a16zm~$7"V sYčH!\Vo(s-L\ ԶDlّf4?HR5uu$3)i3s B<^Gª('bE)+~cڪq`r$yJkZ^J6wYR2kDwdLF7fz #26n,c_W=ɏ*r01)#9)Q22N'ėO.X"Y?0)*G8A+͎u86S䙭}[1?xjfNaW\{Ժq"xc`0b(\ %xn;O+~>_xtٿ7VN 1W4Ot*PW7}oV$x:0|̘ '#ĭXu>:6V.*^ 㩩f=8:5gtQ ZN6->[Q˱s͙ycf/ySi޼U'='Ι˝ܹ2ʟܥQ|U! tPD7ds0>? /rklys8'Asx&`c.q3c¡.v :_ Uq/x4A$)E[tyN`L+#i`[^^x\i3ѕB_~ckʾU70$g($a4HuW;@lnw.}R T$_f}!۵i jc"-Gq)o }@ &!ݕ^'QME\^x$Ѽu$k4z`+.~$bs]BtF'O\}}P1Lzޤ9193<3Z+g/ǎGCq榃aHysmaL Wg 0ϜA|?hdk& wm+aWHsklj3lmzؚDi <9sJҏƌosA}ޡ ;#^^贓8ۊ551~ꫮhأ:4JSs ^ qSؐI=;P >R=kn=O2K^y܏TwM_lHc 'gs2/0`UWr^!0Ps :R։Zp WPr ;Yv`v@m[@3#o`\ّEa [|)`Sl#9LST]~Ae!7#os<NL1 z1uӠc.N2q2]'J7:ck&ԸT9–;~2&Ԗ܊z{Oozk+&FOf TaYP^k4s{j~.f^;ظ{"d t7 ڨvum菂nT ~b~tt俹SGT^wVc!=_ڋ $2ئ僉7MjRxEoxS6Ai( HX V~ tFzW+m;@nx0Y'g:x>2B. aT@ۅSoA2:OeǞxn{}EŽ7ߵhGvRn쟔h;4u+fy\WSOCOr0P.S3SfsKkgcLy?8Gm/8t/alFX|d,=x{կ +%YI 8.\?h٪Ys6'&YmYiiΗ mR-ٞl' 3@砍J^b1IYA7ow[sr|TY'5rgoeJ?R&4m45@6Z}*C6ҀYw#א.@iOmW#Ln!&gf?i~€>EYZ*.ӊ`qfcT hd<% }g5Y?ZR17эhŹ38܊wԍ27-Xܺ6aZR +z&yN30'}"֗Ww3gcݷnyCw,y/N?t,kգb|v] )9ODvtC}Z`<8V{yV0;,L(`,gubS1 ʹw1tK^U.̃b$!UU-;/:-[\]Q1{18bP~+f?>ѹa\ [ӶM#mVi<~ӫcsO{rO/-}szc~|VJœ2O>:o8rh*&ÔO f#7֡9o*i[>ſ~bl1Bͳ)u%ǛDLH U ca[%B\V3H<ɈGOF|=#0Rk+~7zqsp!l#w* |}S13?+.Gőn#dsna..>N񒝜b|jaQ" HʟXukbvz6|τy44xt&5q?vC2x<<R!+yՙJ/nWɜO8{]%mPE[ m8S=e8N8z!\09`t'ZEEڅse_~vJy{0!Ua#&3X\U5"&b Y* ʉ"|yX :=-z֨a#a |JRƷ纙*v.;Su@Fc"Z7&xYy>U" <'w׾m+ooRmlǶν8#LϏOiBLoR O|[Rdq /,򹋱Ϝ#S gĸU$4[}й(W]|C|rSdct+/Z#g4 @B^!iˌx0#7)ӬՍic ظΌA+'LWL=2*J 9hZƀ&C?A4 `lt >3ӟHc>86> >7=qǭ/}Gnΐ'NHZexcmiw9]6>x,>!yO?AhH<#BJpq]g^pV^#}䓭ߖ2k̩HAQ)싯o~}~9 CL Ofï\P2y($J_:eU26ͤ̄bc(;H :\-h;Eir w2o) y_Źg U^׳$=jNXs:V;qn<Ԍxr}4X|Y`3NtPtЁxɧcᄑqKq+nBҜ,+{bcuC}ra%̫Y&dƄcϠ8۽P 1̡h@o".8#KX! b܅!/-+WFOVXi[lr Z8AB.ՋMizibrL[!>]W%o'YkF{7@,q'y,-"CrW3m Dgv|#n99̗I̯)zsNsuez^.g\$F'fDf] u}}i ~" D)1M)a3vp?s? {0㫓H3Ӣ /+P[IPЂUIȤJBs݇*H<̝cH.F@@+x;tFqؚLC7RvO} #y )K2GZk꣘?:P z{^*Lp}OǡۏDh}ž™ 1g&V..wjCq+RxW%Eh<\~8ɇη#'y#z~|(CBYq渲29xXY 8+jt:ɖ[Y+WC[RvCW_wss xus#4||o/\[9:faGI2ܪ8Ws+㹵eՀ10`΍| $~PJ |dYM$T-u絜9?Frzp>ΜGyG."#!"s{bbfvO Ƅ>$!:f]vyಂ P "8q An Cgl >zh _9Wܘ.n_h^Z47|qD+Q Ѫ SHvJ{1\7[êI:A2:N>+ )n웏3?)e'=u2zW#bvaWϝvn}ɇCV>~䕪 wkxqD|@9$A8Df'o j7<0P] Q}58yOX r = c%C(( ac@iO@^(;}SAO+ B nwBA燝 <7˅᣷+Ν_t؏׹Gρ]B%|+hK4:o ߷ɓcNHc2 s%1 -gTX?ʎ.#׹W?W=rszpğhoSB2+ %gEh!z7 eoKg*䉒0.H,m@ A,}(wۦ?*tobbIvHK%[qƌ#׭>:3 Ʈ^P{uEyd7:Q|Wܺ4~9 ^;ҪEJԡ}q'| p֣h[t|-,X&rЪBLjv-n+SZ߈}8n~+)# Jbf^™e;>pqƫ|<3qp&szc>sg! =>^ 窯_uɐ6^+=+* `EOOl9qڿ7o|;egI^gXR3\%?ӞSԴ=]h>x7b$.GnQ=:ךsg^ҳytŞyn̟ Ges򠑝*"r}YBI\uĩKo97 1_J !^x'Qsf6V/O<@z2RЧQ`4hR`fCY͌F$o[rЎs ]P5nKH'4f/kl:#Sٯ:ϊ bu_Iҹg\Nq!UC>.x/2ԕڟҪ )?*;O=Xjg/>gN<qW\<{69O=W_U 8q+_~:]'?P׸/KFsb,Kik[[YI\fc S/u8t06[̃8u:sKg pu^M}7]9gJսK C׾9 uc@)/?׿3ڊntYw4y8`1X̜V#?O| sy? ci1gW/8'gW([W۫p>\0 }x5g9~=N_G{}1)o?2zQ2 L_HEGA2H:20Fsxo뇾GNmACg5tH, dV?6aLGIȫPӁٮX,i T2'될냃Z HmoR"dxР0jNT$.jF8r-Ic :ϤS@zm)u)qգ\LLO+kfrbmgĔVdO0sح͍8/DO|agcm7[IhSzGZR˺ 4% Fg%'04X#K)\(<_J^}}+Z]f9(¡3ޫνeN1< !\ߣVhJ=7lKo?osMC޽ҘSfdFp7bhfno`A,Uyahn}cfɸ/|w'~i]xsE?^苓|b10=gm)}c@/>ᾦ!9 <6q@.ryi@<ӹ]\8Jj\( )PF9S >z[隈yI_T|Vv[;xqE"/0+EV&5r+T7>c2e)@?NY5O0yBѰ }Uq| ܨmhU¤>)X봄s~#Ǎk3vM&Z0c՘QsO.T34œU_hsT!>aB`PqhD Xi /٫e_qqأVW|Gdb4 '\hXBRׯK_Iq2s/Q+Ց|'`> }_=72섃a4]61FR?7]")G$[&w/HZY:Go+7EVɰOMPç/_ ~5o$c O厐ߌ9S~c/ Xxs^ g*iS*\<{g+zLPp ࿽+qp~o &dηs$ 4N"(1"Qǖ$BEXA2WpTLW^q($%eOga/tH q(^&s'&y]0ؿEK:GVkn&b_ 4JE³@zʅƌ[>b|3y^.X8=q)X]^Պ8{Tݻ_+|SO. >sX^Y;;Nɀ3'N?n%q[$!"[NƑ{/|TOLlq]Ŋ$-\'B ϠG`ЎP< %,1>wVW0mOk7`._W--Ѿ$Z/t_4A9_>#n]Ixz`zϢVDߕ|GC>M\?ctXبW<4 %5q`/S[qbW2. Z8<D،x&Cn&D q*%/ l5kK]n챀Rkkh;V)P~ʮJ૬S ېyҏAW+3 +rk{"$ê*INcIH8M-)}u Y>-ht,YS9e㉼wcmÊ{RLL`h^qR^1s; ]vcQpho%o9|q nuzv}L?/šxqZ<46ޛʈ+sbEάcX\uT'yLw($hKJ .tV4&k~;ءI+=i>u8p[mO?B^QdxXxF(q=#NcyS؋7zWȝ8<%)stҸ(OMs k៾'~'cfJ]JבjhVs4Vq>BhR%RA/C[ AyVD* +26nU5Q7~?''UO žTtL#Jnw}p3 R( 7"'3–!}(݀^yw N>q* ">_r `>'o KcDf.QGce<$&ȓ柾FJU&LVd@}Cp^Q _@C_'Ɵ+:yg:$-`*%̽C'0^!粬Tª;s8_cL簮,QT`Wׅ,8+Z pNL 1 sK&|]4BN-}yjտS{q3Sc~:a8O+ߛo%.Jon꼫iS12+K9V9޲g$)`OqX';~L̄V|9cVث~V2hjtz'Gz(sj!$VkUV9u~pۦ\G43M+w&_]^9O'Mg-=|\3eWR|r<0 yp,ړK|mWUuNM(x/{5~ |9uN:;F=5q)^+=<ϥr3\}13suLvU(2 n?*208B&ӅWn{Ƥ?6j@!QB0]?ֱAqu`^K2 [~' ~Qo5ؘ1׼LM}LJ$]g?+nl4֦O 034r4d?y:+<يǞx{ss݊wuu%Dž Q})V(o_ġnDlbrn&q4XLNO7m)М2km{^EˌS_6sb܍V7>6hu!}rو Vsp1J[k_:sɲrrsOOOY3VpPiH80zjHToԪ-wӵFNipOczW<GCXGڜOL8?ŷ1QH][^܃(J5\E/'c< _`W.Pb9Rg_)̛ X˱bp˖m!|S7~] :շ Cf3&Rᾒ9dLʌm ߒ08Q])ڗ6 {2L(GSA8NYQ#|M] ;K|\[n-z1mzj6N:c.wg?qmw.]PN>la=1bC;{ת}<Οz:fgM/)}X^ZW|@uuzڵ'bq{vyҳ =ϷKUB>BP+~ )(vPd4r;\߷`5ow~}|ϡyjfZb#2粓 =󇢗c۟4z>KPq r-6ES$HH`NXsLrڬo -'cfdm4(CW%—NڹXkDdXU%wE&b;m@&b7 qfz>[r;S v?.8;?ɸWL|ǩ: o?@jirETe$fZIY08 : f L/22_`Kcx3Ƒfg=c^ ģ{_geÑc!**QFAcјolń7XVW}i>>) X6tyr %*s>( ;2{mS_6VbsD5F>''m3BB@H6Y`h\E?{bMV0o~2Ɉܸ@)"ɿ2QܱP T_sAW> nCid@򵌭DQ{7xW/ÿ=ʵqE~e82K˝xU+.+zU{Aچr7"`p)9qK^󦘐05~ܤ"d]}_+ϻ&(sҠ>>A_S꬜%pXe)JPE|뗳1>Htޱr`h\%8qz5^.Ne`X"z\Z6iw f+殏5|!HUF W\J|LLziP|k|+gױkk T 퐀I/p1>G^N#dƬ9 #zfL&cw PN4+{D1NR`q pb'?w& N1gϞ=z7.vTSju#ڞpi@`5hC}"j~|NU<7u1b4 3tN6UJ[;ĭ8}?)AѰFr t76d>pX0d0/[_g{^yio۱ L/XRg?>rs9FP]'Ow4yU_ǔ{'(uV,<Ji)M,)U{|Lq`s@ &+(1+[߶/n^lҕ@ǀ1BL}1 ȬĊuDmJ-u.K ?ޙegx'>19Uwuj$%ťs|.}:Ǎq/2n U>-yVGTz~vqE @'9w~[qkh!"Իhq:1CRH^L6هMmhLvFPg͛6 1DBFI&.EZ7I%asp)WF5~ь;_X> @?n<2oܷlp*<︈f ':xZAI@ ̘/?H 37Ч)f:p`쟛Њ'hE| ^$ ZtNV/fϽ}6Vr埆FWMQpV$W~'ҩc%RR8 ОU4n5 :YSIY33uF0ZcП3mV]^)8^%x8x=5z`Ќ ZϒWh=WtPx{]_W66?31"f7׈hx pqbe.Ii!.n€ey@KM_@a^IPar?ϠKIDAT4Jgw@j+Dy(̓y:|0:!W!aHΊF90o"LXGbeDE#t$x\Hv:Z*E GK\µG_01+}7uVLƴNx{- 21\.qo0`~9&CNv\N5|Y41E,ƕC۽hW^q?'ט%$PԝO#1W:!e+!}ʴW HTxsT<: of9cœC޲WOG R Q|989XjJ3]!Ͼgpx)8d_|]~k$y%OuRlOeĔ} 37zgM_wuqP spJ5ՑK$Rޫ)T6]|SG8. jCI4&7}t֖bscPS5Ma!_rXO -~&E_?:p_ Ƴ-+5GcKKK;_3ӱ)|>D&|Hyr@/uڡ~/ Q*/ A7R]>,|2.2I |g8̒ |i3vA-8E^A%RXq|] +r'(TUNpZֻU|Rкid?5p3)0aӘ'GZ{R*hԩAnB@^Ճi'1l^{X7/%R}3 ;Q_ucA(}+p  R:p[ @i,%dKq|l 8qأ2 >~q̩C CȆMs/`Q,v .خfۑĒY ;uk7+b^JeRwK:¿lg70Ŭ3=唯 0|Ϗ<#%| xTƗIm.ŝo19kyf;Fk}."//O#77: ]zpׯdLk*@۬V[p#ZII. 6@’ ?A>thꗂ(rb 1.Jat^q*1JF@IyoeQJx%Q¼>4 X֡K)K/ σ6Y%K֩0Hd?.(GmD]_.exDo)N|sqYȖmHe_O/H(mLJfEq+}|+OWPӊ%'/S1&q brR2F`I $b15k{sp`im3nGEI %7՘y 1WRT(PӔJڊ3oc0 27rxm&$FRs(-doFi@/$̰š?cqd?hiJp_„ ]y'`SHĵ֋ CV| ). o2 1ա73Q; \ zjLUr}A,M\`;,fG5~̈́fS'F$&cs鼾VJ9aGLhcu9^}U'$%Y_N󰸂1Xdr1 G8d#Γ{oveC?cfz ~Ib9( U8I&2 'R@!_8&(w|^&@tk  .,KQJWq J )Q#]'(.q`#a<}þcأ<7 qypAV⥪1&ֻ^QrcaXX{9U];SүrY+R3c$p‹X 1rI nt+u4p͠v1ͻ@,R~ep% mpb4gU|ԄݙXKD4)I5`8Oon@ʉ;sؿm_l@N ~50 b&NԆ&.K~.VM*k/%pp8xq)ϊ䳟H kPw /=P{]{e_Ϋ16)z W'׿][VSoXEl0x%Ir$X?<0?yܼJ>l5l4hۛ{8FwnC3^1-VZ42s!Tv[=aoO9zp̽~1?7n"2LT(rMap-LDITbu34uBE1^6P4VBz9:ڲ/$8 d` %5s DB® /)p.K< /-=Ώ*9u<Ξ:a%T ʦU,T V|o(;VrFA=ύw`(w }ޯ4끢y}r|hM3'{먒0<9*l=@1wmɭ4j}[cϾk"ncd,='@J,/Μ切2"-mnlǞ[^Un?"Q?'As1R 8~d (O;eS EIjIv}^mn@Qjw(|dAD$CIۙZ|e #K i@q;:g/6d p@8+Cʋ>X䝕q1h$FD5Napr"l3^x7G%I|G {Rx}Ny|Kw︿Lq2[FI#sFLy9:h^c|1J|dݻ 5ʹh-%?CFec5ޒ ag C2}s=|VRe +| .J\(8%O4xr\XxƅBO}^K X>O!M V PKgPT[l" a2'APZ5"ƊѰs@@|T]W郀{,VSRND4"ܷ0 2Hx؟0}&2IbN7 ~K0%?WQV@|w+:j rw+ڵ3OxZX|Ona9_\#39nG3 04.oC-V$c"@l ,n^$, l1&VVNg!0xF,ĹꑲnH`m|~B{E~{/Wf~ʔrf ዂFĮ˂ "92+bƫpe#SG>! J%?_5F| TiTx'honw_Ig 'C̍G*?-) (|1VxMq.#5dtw|G_ юG#sR& 1P) h '_kC >έ7}!Gecp Y+{)n|n0(b|ckpu{KI@xj3^Niq=ʆ0!\V@7G0AH"^V&> |(e|z6&y Cx7?uoMiU4equ;S.ncM;4R8+GAH^YSU0VT0V8:Pv$_dY!pE ȁd9"b@/LPȀ'Sʲ,J -,Fy%S8km%*؟,ƃt8c1+OB˷4ӿp?11 Z3 (Vt2 nlHj1ֿU<-@ɞxoz$1-BF0hfV@%r$9P0N ק]qCx,Z=CmNÉGGE g2/&rۊѕA!|rN刑u%<0g ˃#Q}cEsF_ah|[x*ΟiESʚAX; [l7Lr7x$ lePup31a$|Aˆl:N@+SC8f% I0^^X! a f\#jpqL'TIAt'`*> ȗsSŀfҕ^E-7a|vlb$c9G]ʟJǦ Cc _ӷb24E$3 J$&>"e?nՊ_nM _ƁyTސQYLŇH]V↦$DN 9da4͸ZƓu(ŠaCTVLg[8xEZ"wO\HTNDhYHH4SO)w<Ix$)hwJLw8r 9p)p"F|cOV"8PVF: 0}(4*KJAAҚ1F7̸pmMPeR-+,<LNac$f 3!uY) c0pu(6! `o5tt++rSMFN6bd#3'D``J,G7BXoOZQ0i*)ˇID+dvA`+(R˨1w0!<03'm/e2@Gx \ LɅ) ׬xq{$H*ey]{q=:qbc/e&y}V21e`IVY~{|C"Gᾘf шM)Љ즤P'$q6`OfF 73; ŠX=1A~^Sⶏͼ.\ͨp(/\S@Иy2Tc Ru40g‚UÓ;XV|N`/5]VI(r|L3ONV\ZKgcY9A2qƚgz1R-eܛ8yX]zjf)s^kJq%U!F RЁɔΓH!;~D{ 㿹klé?mNcW턋/ JY ܽ m ,15j0KC?g~Mb-CxKIEi`,F]"ɲDO]-nkݮtTcv4r8Cɳ1lisq0P3)ݴ 6K @8#j+d4GcS߷bc s[Hi^ |n6}PƀRb4JiP_Tq+P@u;Q0!TP"%R QbU!,fz?@*Ͳpb#1 #$7lӮJ>gSSߣt >2WdhT .eMVԕFЯ. Sz%_0i5LY=PL0T1=/c0Pn;' jZFdQRņ02$9Oᙝ)}~#(7,8*  Ek!.L@3 jt64&mʲAyf::UƅKh,CfwZ~˪_qo04=Ӛ$Jd@2[({g[%K>oXLypDNM#!wh!=vbb4[= @1[CaY~lDB"Ca@2F@ǃPaWPw0!ex(̑F6+Y o}_ȘDLum#f3}7!ԠҾ$#١$wgtKy8α~uuo닱i( 0L_*oOEABiY0N|A(z^k|ƨbu3ƕC|:&EEAp'cfKԫ ƏToے1[F5 Yr R ԉ؎W!( ;DeDm,1v71!4.ށ9İ6W d !?*IB )xΡl:kِeiٜə=t*[j6XH5dl<(E[r*RΓ30@N.VoSP(ɐPm/0T.k* /E_O7^ 2zё2^,ܢ=T}rɓ8SzK? =A^O9/TY _Е\74^ JǏDS xs\DVf )X5 v znt׹O(?zQV9ۊV,"P~hi?O^G{T/~bNX&V֯է43A}u{p#fWq%5hZ-d @B;9h}gֶ+8;f@(B-Ʉ;Z9vEyJKIȳ/Z+;HJ)@(/R#;`cA<ߘ2΋  9` y5,GmBO r Qp+ym7bkJPȪe&kh@AJ_uo:pU ?q>.'g]vTTZG|L)h?"]P'3J!L_ւ:@ 4>!|EuRo;#my[ #d5@fqC#`/ *5jLb$31+8p6 S|a\""| %]SyeHc8e&ϩ`H=cҗlLcE}?p}^إƖxHRF0iQ]̂Xjc< 7c JGs\>۫|ћ j@+;ٌt3zrq5׌ʠ+}KBڒU/vhx$F8`$v F( F3gb+c<LRs@VrBaW<]F8|JzU^gm3~##]@YҞĻ?Wi-7 ~z|[}6K-ʘS$P.lTʟ4c4w yZ($~2ʠ#֨VެG(>0; ]a!@`a(@Yz<%]/|r c$Ȑ:Ģ =] 0`r*]R9ofn2b Ї|3 ᥿ r6 tzzp@0V`}d0P)FDϘooO@ _ <입"kww9WS$7n>@o)YN'r'B3ϫ}6+x3N+0QgLGc!4 wcJ#uoN vLb.#l"rxM@] 3wS&th"L ҽ}po݅q`%̵NUjGUGOgAFQ)f|v_sSb u9|& $q4z9+/KPLsU3!|B9CUs n%J5m~xx4\S.W9MQk"!i"B~=+J~6键Yu2qʟ5 m7_~_<2weD{軷 -i(h/0ofߵQ8jIK*,q˄$'_֗!o"[ZN/wgԓU0lg` ,#DrkCCAYyAcl4.#1:m'ѧլŧuKU)8!Ġ=2 H˕&՞Y̍P :,pzQP>P;r&ln#SK*@83HtmuJu ѿDYqEL>&A{4+|ծz榚7~&Q96qS?#X)Heؒ68u'y9@n/άƗ:Tq|<$vqnoi vI2g8p+ 8X)BBĮ2'|KTGzK9TTu>'|*1zť3nTrJOٷsX<|eG;O< _B`U+}7?}_\'J*#M)]Vvs^dt-A31Z͛34"8'sFX`aFb{]ߓaۿ!̀Uu .Ϫ}R.;wr O lM(s2}D@> mP [?x*fi_=2;bj(nG: 4xd93'q^ )T֭<e~2_N`5m/FgKɯ t(#īs!մ(Z])@<ƒmZ?K$G|RaL{@8wUG)"&@(h ׭25CNp{%[n3ۖWd?89\6ӭq8mK |50cL7jEkc-o~e6({6̘ `eNfbA1I!.Y6:eB- {] tر*u> ~Pu& O 4!#LJ|v 06SUJoz3~7bf`TV-0HT>~BΧs1q1u C$ Fgqj=Fcs (% ͵s\_^,'/‡/9 KPӌ7StC*yN;Y7J% SUpϚ,8{$rҊZܮڕɷ)3OZQ̸2A57AG;UƋo<&/p<8|ϧ s2mC|vy($Di /CwFy_|.751Ҏ%p}|?'\*FKǸ cXF[FL Ps eӈ5ӣ-u-Ztm!'0@P(k(o%tuImw@6V\hi$l'nH'j:q <0xa nJҟ'nܶg \GKR:Nb6 |g$lˢr f8x_nwHvZ(J[tiI|j xCT sH?&  q1,X0ˌRsBW֯IܥԕFQK(KFY[1|Ǻ3CEO#Z8ӊhވٍu*S, @ 3 poTx"x~˃e0}O&l1Y FI?԰a0c:xԏODJBCvJS(A^\E+k :?לw%V@=OYA_n) W맀('6xǁj#7F##SH#a94,T`3>d\\TFa'Ց& WsW=vo4$^ʣ^HJI2.cH!uΘ `pȼZ_K*<#0&r %ɈZ6( O+qCCW +„ōL*/otb38MՖ+`K U  jWS/#Nv. {$+}>&hqv{CYL',BܙJ,m0P*'8!9֔%Os\-c B3< g ܦ|qkU@ WY!:MVĨXu kYVO)}dV߅a%gy߅ <ߜUIF_<^'+/yupGcDO*y2dXfYn!$#pӋW- rRAg8Y: ɞ8勋,3*}nC6pޔ{Zto`^i c]VUO!N8+dڐ0m(a BYЍ.43#\U0Fq(8r4@wj*i AA EgGР3M3i#P򪰮a:??*0!\EAL*"XMN婞>xnK*N2 N~9W& P;e Q8m z|>]YZ^~&͔ ) deF<0T Rqs9d-F%l>-mdeݮ|x\}\Ie36=M> he$0?9uGdF 22=֦_/=ڇ<`9b4//L@qf/aOzblP:1.D(~W(<޷5!7ۈXtFt!18[Rg_._=r#N4?t6Z£}o&—C`X8ja7H/y@IVvN5.0Z 0K9pt|pq5mHe:qNv8%sqU(몞sRВ$$ԮT8/\a/QO^5$(ot 쉛)ᙫ3ׁA®+˨"ačJNt;Are3 >w/kϓrYGͦy;FOErLe\k[`zyɞWCx03pi7}fv\REVs]!hU bR]!ܭ=h1hx;D –]$tvLe]ŷ٘O2hp#S+~$r:p1;}#@1+3 q,V'JH> W|e/ ] CW6~ ;_*ujؑ 2$|Ż"@;Ӣ%ݤEBAg6$ 'o 9vq$-sk/)^X>DW{_CGi= Ƞr49&Ake.}b?׍ىX#r_$pרuʜϓ~݁rI?e?^ NFtd80÷LDSf ,o">KgKfP!?O* (u4$BK!pBw0/̎E'%n!nXS0 Te"-m):;9gu)D;< v: 3K!%t^x6UYEYNLI7D[ x8 ?e3zTf4sUu(ap.<8O*o;=._<Z^GA >kdEeq_p6wBjFZK'e%&8aC>u9]wBu0'^N:./ 9Oܛx3tVr'>֊iT4|gt4SОkjEȈddJ *Gwwڼg%L71N)sˋn<`߼q, ,(dHJc<%@ObVޚTU )b+gF}%{cy@L.[p(PΛs y#~q*\8Z@ CfW}yt4ԨOI'jS9>rկx5 ysd9 ڍtٜ'MAWQkHsrР^WӍS_]vZGuWv0W̧ ⑜BA+KdSV|J>EB]WDqxg ODb|uf_pOR$G᳎92#Gh/rNO%|3Z"swx w d<@k+%fkF)+@([5lrD=e!'#­7X"f*XaVޖ( FfDX/ QcϊIysw@L7vu1!FcD+L;v0|E1wr+!GyX'rbD#+t!*AaShY@tّHR gd;t;?*cÄ?vaopvuVp5yMb9äx%ϯd@R}R';]ej[W yВnz\9ܼ`(i׸{TIhg^_k[##<${CC~O?MG$-xzԧN4_r Gqvu`\Ǒؑ\C?|ѯ#nxion[clbř 3 (ZJWưR0cc'`W*e۾-TJŢ峾[GVER̾)&hd Q=J_](s(̥zؠQiMԪg8LsߵP>}όA"]׮oIïa33|? Uq-gc]:@U96r*'CIV6ɼΝS9ƄS]CWOGݏ<%\ a n ^trW 8E4wHqʀC+o' \Ҝo1y%l2zVY%+e6lq)x3;?wߍ =ɔI~x3~Og9ɯ6Wck+Qe\] ƸܔظyL=|Ip{mp'98b 6³酉 e:*R6m3)~q ie,*7lć>s*3R0SSV6>}Owr"٤ 3<gQGCȣj,e@C0pxi@'@܎y^ĥOj+*/M7,V|_5VNhOFSX`w#,kMBVqح܅')ѤPC1piC؆7S? q^VbSCtq s "Q. p7q x(o[R_ةQOId,4OmDF۴:E y}c`q~%/kTzF~Uv GxB` >Γ$z&]`r=w:w+xqKc2}WsP|:ts\w~8k\ *fՕ4USHR.ܙ'Zvsiix$NS۞\#}[<8a`#6s>F4ۭ|ˏ@+VeM.qq8{ HNN<_O]? yCJaGPx"a9&kP妼Q)b ^R=! _7=oSp8׊etcwQ@?wT&fq +w,``&xm션hndS̉G8^Q|PB4, -%'a<|& Ƌ_@ْ‘VuoetdgU_]WڲH WgŎSiT@ \+P3@}w=KX]f~IǹO>4T}VTs!T&SRfGY3.u(R\Ie J.es,5;Ÿ7y jM Kf4$kFG+_8Y. gLt7bbjZʿ%r^(Uo%V4ݼj_,ē$<" c!<!<S|Z1X/cJڬd<|yӼYQp6$\xȫy0O5]-BS2%#R:52dň4$_$\^ {0.f*|$9m R1u؁'R*K}W/w5wޥp`9"|wpcQgq)q*]ݍ Ǯ1<K}JN)t~PiUMWT\|tpE#2[.m'T]+\/&xhۍ; _eҗl\g7qQa6.OsO=Ss{<>ok.qXuϏ䘐+qݿ95o!\/fhZ~-^nYAV&FͶNUv*}DˢUF4eXM5~,f)hذ?,p)" 5)z3+غ \>[8P &E3tFmJ ̫O?ڊoىxפּ̛̚h:ɽ-pEɗR@HTx xWF?4tWydr><ty9ٸU:Е2qKm. KQwup@]|VgTv8%Ǭvs#J%ϧ< KpLtiSDl<+aA$ݦvejp-(G:2*_d22CZu4ߩ֍#!Ģ#4XP / X9w*~"_7;#71Ja\ҏ,oq*(H~ʎ2C h^!<;CO?~7 wګ&=@,d5+پa$(|Vc93byfƢ>*2DGJonUݕ@M~)=##HPeG5f#1"g8Wύ\"';?|6?x"ODZɗ] 6$*C];,m4dq )C&GIhK \-[$uʹO I:~qO՝j^mA_`><Ƽ%{O$fa+(ҘFҬwwd1$8|Tq޸]9¥n?N 36ǥ3+7ۋ+32Б- n#g}}`xqUb +O8cfnNJ][RUuʾҗ€1 le{Zv!\Xoq!Y%i"F|ECb%dEJ;]C:Qlgm ILw:U>_J<5S'7)׸(j/q㠬x eUnR| mԧ0yx{[pP[(}uF`FbLe&Gcq^H{$~kdtp"nJ { gOO ThPf%_rpYbZi¬ϹzU yMMI'|7Y=w}qyr65qr?zqru4&vcQy vs71Wו?M<.Volok165)kښm!77ֵ}n&xY?C|2Z?~<_6bWh3s?]bŒ!F&7R%D +5wM ^LΌX\W?21M\.V?;ty8JvBeLRlYWF_l#sqcOɍCō|^|3>pFTGksDGP'F}r)Ht+{;:NuƸJ}_r}#!=9Pus V *Jz08rφ;wa0w@71i< %A-'iL>mn' z;@NT,ӖP|Q/&u%߀:_^?~-#'?_ 2 9hA69׹ȫ˵ q*(̢aM2`+_𳹱Gxyi)6[S3k++櫀eg,r pp"ƀ\_~ fnÿ1>>ff S,Þ9f6+0 K"Q0APn#SGa|)ÚCS>:m[|*jTS;l鑼r*&)W|KAOa>dɤaBcfG+<_ [8z>fwoe)?6"!c `[V*Kg4>ӬӸZ8`*ULI=<_!$@8+4d)G^GuU!*zLZ$i ;z]eSaMwh+>9tOt_h鴥 O!7`\ tK;<AigO_^o?@ưڿ- .kHvpӲ (M~U /"r_}ʒo4b|b"''DĆV /Ɓ1;|  4 ױgR]mJ˷@-F;e"81 Z[(^䊏-7*5S1.c_S;Nj)Gy^vQ+ftP-S жo\jE +67 F;~ Qŕ2&FSf*Ս, SO(⣄A1VqWiC!;4!3#qfx-jTf'WE#׉A퀼.H<k!./]%UU$g"=Yy+-ŧRJ:fipQ.tOm&MJ6U?mCGP*{Q>)]GPQBd+~L@dkѕQɩqɞD+I+:+4oS36HcM+w=t33`,23Mc|M} Pg>܌/{3 w J%z|31+zl̹A+&G!KUi$ aBS 2Ձ1 ]H-vY1J|3g+A9bfeƢ7˧4S{ıXZW %TGf{KK?7 s 9WiJe66JZڔ+K9%CxDp0"=% 5S"ʆtqO%+vvUz\#Ͼjq:HڈEE!_np9B[rHYّAsC-GxT8:A01)K_ٹ9osݿ!8Yqf{&BZ?^& 8wq#~>STG 9v}RPPV0%e 8Wi0@K]Է8:=̞=c:ZFC~;4W\"_F aHte$lq]Oi~g>y`77>sS|$aQ9q/ @1}\ c'O_'#}?w^X7J]4l,_åOׁ6覚3ag$^PO+ ÒɳrD0!;мw@H6Ri3sa[z 5ݿ;#Z!MWZaV~? ƼoBv G9JE{S'gbzv.(eo#01Ə̰g %NionmQ9s/;|ov%,fW`jESbB 't-OJհ&Uh_:<X`C<W+:٪&3@9VOOy2M:U/Mna@w5L1n)HIx_0*ce"lmʼn3#k׈cȊZ@*R@/q pBD5j_緞n{†ͨ?Qv÷RV_uZ1+~m.G0jEI}m+ܾO3/o4bы#G{lČdE:wѠ?0}brA{w#2մ bױђ8(zcw7j}c}TVԔ6%#>{brnyCx>~8&Yj(BliDgB2,1I@43BGt#*3ٟ DhRZ_T:sJ.xtfeas9B; FyՉ`~n2TWPFv01.1brt%r=Cǐapcm+>?u*[KSsͬG(^!X'q ؒ * k5|~Ig)43iRtp-)K\!:;}+‹~d2/G IWǧE_؊=RǸ+=ƿ ~͛@0UKl~<Z-ɘ6nd#ȈI@10ZT\WxDwsEV̿FmN7 y990,R W>>od˞'zl5AB^Q{l1_ޜkXM(ŌIC2 a!g4^o?oG>rJ P 6,I5 as+)F4;1+wAKJS7F'1Sa7 /I5tw3t~gOFS3^r::|e>o׽e1;ˏNJȆ @!5J>Qi |qIC&5P|0)5O6@#ӡLSٚ<ВG,"wM>(fhJo4?jx(K3J:7CRgύ{?QX?("73M|ғ' ݦ?-ʀFG/v )^^d+vJ{;Axs|D/Bsb_BddWBF.u/-noWi1:o{.&dTmDKb6=| O.(iI+`=8Fѡ?#.Giz>]H,%QiI!-}g7/m&푖0/.h|qӫ@vo^g?o_2[{laDb:cm0n D*ǯ¥V9R!zIN߹Děb\c0t/ ghtFw%*ĜP:{Ņ02 /q/a|_8Ve 0>߱?n9s,)V==Y?U[(L W? !< CN8'_K4ح ӈ';_UF%̟|zWDqSstsx;eZSd~Di6?ݎP/7G1Cy_M|>1/^]ȕ2 #h~ m׏olɑeW@3Z[c~m}7-X Ɯ6a>/rz6/ioߎ1;5[ma.HG`9:\#gk',xg 'Ed%qb&~G]sc^-{p=€FO-P⍧es?/eIտJ&&_%}Z>s4 t#u(a_Ƈ0 ,td N*2\~o_îQ>N?8wd?1Kơ/'ՎO؊id8f1A] }\*)3_4Ǥ; }BPxu05o^WM? }9SyUi\I*7|Y,C6OĄ)⃈@y2bBnj+ފ~EŞMq_* cƄA%(& <Ǟ^gdXh]+sY^V?}=c2:Z6RZyOꟕꀩ=b|vx_~iZ 5{ 1. ruR; )q4i fz(K榔t!OM(Y&؊0bNeՍuط_q$=13qJ`8d[ agzKYAυ{1;yw5dK'kO+)++g:cZ*W$ eEWN"mHa+SʑE8y.G?W~O`;:ߗdѓ*y bq'QG""&'GDiA㓒U/DEa%x/"7;pYcc|`}w~ׯƁiYLB].`hR @xgl,k`ՊK ]UĞ|JE 3i|,rS%]e||Vu(љ3D^>ҧ5/E4QVcwʈ|+IJָ0R2n 0T'@0skvFy!<*%`AazPGUmxP~+ À;mG-UF2G͏x 4~ ,ew65.D|ŗ?Cg%xo(K ~銠PI]K|>g҇Ks|aK?R8kW~?Zcév9.il* JQPQQN5n+^Q&˔4bz)A%qJ'7$hJjE5=~c~#1)޲̡QACnc{Uڅ-ԯQ! w\-xiqe_ˏ6H4g%>] V0ٹ#ۛwp_N}"#t7SC5NY^w+"Gqp@ɕwz;pg|L+K A(wO)L ʞ萼Ed?務0Bz|@]6 ^ӕOK^fsBRN7rF[|`F]g PF}P ]a#Ȗ|6ApA{0hP:ꏿ((!0(aW=DŽlwW.B;c!G{:O+0St zP/>[mM;n~o;s.&t͍en>0 %y.iGa܍w (yu ahFu\K5 w%et%l+yNW:%-NwЧ!O6ut8HL⺐Q%8xԕNP?9>ڋ͑lƏh#kN2Adfd $q[U+z;փ)yqJfUcq 07)GYʝیGbkSYQn@]{ʲ3/CF``\m7CxPp|+[_xȯ0(_J6{0&aܒೠ*2jIE+p]^}t ȭ(F흉RWRQJ:7uxg@)w2_o9}6%DGIrYamM_ixFϷap) Zz:jL'PGg.'a;@5_% @?`UуNx "'wGZgN*NȘ < U~\L)?2=_AfVTA;_ ͰڂAAuRГ^rZi?;~oڇ@ZZs# |9l j[ѻ^zHc 7 7?6oAASd4m:G#PiOaV~0I: S Iq@Q; գ6g·/þ75{db^ZɄAD` vT<@z$~^ڕ#P r_g y!(LdԱl䖶~i׹%![yFN'tj9Q|u>C7`EsSԄxKSy!?4 _id2 ,PoDK8?kݑLbG_oe7](jK| ?'jwCi oXeZm.?> xoBL#-&0 vil۱eNPR@b6arʃ*Fr ŊBR"2wQ'V҉2ѹF?|flF֌T#<?* ..21BU/1_)8 Muj,^i\OE{ވkm̡΍W,RY~:0/AhZCYT@51>Oʠ vZ[[{f1⭯\C|Mqp)F*? d퐼]T" 8P^X" 5kG4 3vfe;EZisRpj:GefW皃)_'@ ".q|ODdgϣmO>=o~ݯF= 8$ D$L(1hIKqdeY^ֲ8;IHVql%xIIA)ř   uNg| @y:i׮]v]U)8\7_0G3#{?@HhwK3ܷF杴fm~ws/ou9^&(|0_hمȗy2k'ە_A}]Knle<{I`u7?W/_>>;_i'4 F*ܕ#&+~3/蓀櫁}ܧf0q[RW~&alwP2b-Va5/_Ҩ8RG;p˂zV#yAmw^/|lanʣ;~0}7,F܉&< B-0>50V_wUgڷ2džv(ȓME 'l>xKݩ<&&s{:wo0H}]? ok}M~&W(jϻlSR[|̶OwNW59at#BpqDpkݫb b++}[zd:inCpѷa3W-kX:F̈ nF*uKu` Ģy }Lps;L$N27Qo>cj#=c0. d/0tk-8ִ:\g z]O[h~tH0 Hޒ7*rl:!m1bȣ>GࡈC-q IQ{m3g3^rnۛ;3U^qo@v4+aZa`Ҽ #̀nww?`ypMO\hnyG;1Q'? ;y'/jp6O8Q]jhLX5A X;||7Oo̠;|50:<ΉBHRtH`^|M^PΛ崬 I%nqks2ȳLclUT o&תIr;_sD~s zZ5&1H~̴So}ǃlN U _~ʼn?唤J3n#S0hc{|"j,KKR*q׉EzpU~?UqIŎw_B.OyZaSk\t5ꕦl'ol~18o_'K?^߹ҾyO\+_ɇx{CZpw~Хݙ 7x\.8߱DAV1+qq]GͳFyI?DR^XxМI82lE.JCuBчO}|}1Vȹ81"aAX)T8&aD~F$BkC:{x9,6o&}yoq3#NTCxE6E@X?̳s/ 䅷t92x\ ЁQ "} []v9̅@(3wχz'yJYwh۷8k{C擻Qwv$2JH#lc<͂N^8h~ @‰KToz7ʦס#̬- _"/`;=i db"RUPb.L,)nB9NB'(=L0^)R Iu-m=o>D5~NߪMA]*"rǑũkj ,"#ZHHi\Jց!aǜ{F}#=jo_D^tS+`u(o^c<{g}r6FCl!AoxvnPݘ7]VtQl$+̦Nz383% „o`&;cg]>ZZѷW/htɳ7׾W{M+I+X ְ%Ws_#4p̀kv]I))Z<PTQcU 4LS!w-D(5uphuc&Է1X`pt}֮ۆ^mmyV&`KEkɉUiX?>: LC_'~ ؇nXޕC}b )Jh& A`C9WJ ' AHC|GR)1@T$a}@v͠ nz϶t{'6/|VeO][.|!옗Q `#*lGeUiB 僻KorӋ\`GF/t9U9<)))D^.X s$E?=H˔G] " v|v֞h}V;wt.3.6&L'֗1cA0ivCb\ʼ^qIݧM[P*]l!V4AsW;=kLTPpl9Kgw%9JA$ײMPF%dzxy7k;¨Q:{6ycxng tQ-0re޶ ]OyV ^@x#7  νl){]{)b1Pq[ZJJ QTlG@$&DMrR B_x9eRFt}R4#EO0o畦A7:qןioy݉v-[ 0'ZWXQĭxKC # G4/Gthf=_nJ{"'EUK g.OӪ̠9WBbV}h:e(a*gWY#O.H<ϭB<CܔOe{jU cgBrB Oy_2^֒\U B:s*kPN8|^w?2m_״{v2Iˍ~:m6ʤ˔-:}muov{{ΫjGvz72Tܫ|/]]_Θ f.N8|M|epml_hg/=Z)g$UARCĺTZ:\>yA01m= MH-8RVca gLbNO@mƳܴ=]o Ơ)+ߠՉkW:ׄ}v2 &Cvrobz{ܐicgWzW(}[H=ǘD󁪚%fk voaCol_w33gD@n z2f^$SOd*RJ|>k'v^uWֿjO0;3x08; $-2ibWN]n}E@@=&+֋ |ƨ.J'SQ(H9Gx789~y'r-)S 1g`hL7.OLr`>"$ G)/l0'''M'$(. 7G I^4ջm/Яv?*$ uRֶh_Q7 20to}_2ʳ;c.GJ9e⹼GXMHaNc`<g\C^a+!CK)y c- ު¢DRda=14_v^ԚW<0bk^@=+j?kklֶB-Lv5&IJ4[T~$IU|78w_;y~GzUٺxc&CV*65@|  ;)9/߱c;T=JHȠ|vmK=t9!˝€gE̷r+ejGe+@cmW{uX#Ö˛ij;S4bfZ][|D]P nDpztblbЉ^N!<ʐm^U6?EvfלhodvI;Rfb0XO WZVcn^B̿O~4*tt̙h+b1wT(/!MYG6I} ;{ >o_B>׾rq\dqCu|ʼnHʪHM+++3 +ڎBfG "$HYǀ㕲& Q~lekKpȀΊS|O's'zA{9,`m{}[[?8ɍp|ُ~nsϡ+uǷDS2&k*pQu{k&-^Q/۞|n֞>ʤ8Atۗ+6;D*~r!#i ?.3ᡍNRe|K^yA9ɵL IpGHWw[?貽 r+p΃t!'q3u[=L(. w{mmԙ^U?Ľ&{_i?ʎ K&W ? C#{b%Hd{kzGWxo/mtyS+ C(ckΤ{8}x!O9Xe!1^̈́h8_3JҗeUqy*/N&(#wKWV+o} aqqV`X/]:; |6}Vʰ5INFn|Nl SVcENQD!A, O6;a|@[&;猧(tz;J7䤏ړԥO)eGz^ߞH?VX/c_fef?UFNl[M-gm]n[no^olOMY[ۓ?8NU=ډ*8Q/~#}(iYU~6{vjk/\?hO=lO>Оk/^m\ZZ}=Wz52dgDVZڔNdѠU?_;qI>aӌK{IoWD%|OWPdcWvgrPPv 5.K?x.H.HNfΟ>l埃uZLyʛcw% q҆2e6`Yg g&o*h tO8s~;:!5XO` UaJ;DkG@i w&>~:5Ui+*o8qe|;(tY)96)'1 Z2 {y̏t2EejM 㛉00ć2 Ҹ:;f/> F]"{G Oxy/D) ENNt~ 0N57Yeb4:а~|O! Gs"UyLXpzmnhEEG*7vHd?QCh"kU_^ dȰQ&UtC!"]*c8-04[pȉm B=\#1S:r|9\r7:Zog'کvz;wjcyZ;oXH8i?z3ߋb){'\Gv0T+v0tWwkCe]ezmvg|зnU+ n[ P> y(ȯr".+W#:۶fRˤUzoxBOh/c!ytV6(N/fqw| 1H2 2տ:Mhm o[tG ^iڿeo]o u}ǪF@OxN:72#Dt?vwۛVx{RsrNFзUs9 tFFbpr=qAiY۶QG.Z H?9̬;eGd a8b2$\ @ug rbs9tδ753: +IJ\FU)2F@C#^]RS>; lÃ,/bJ`OcKv;rƭ!^֮-mǰ{ǰ#CVBM?+g;Ç*8DA4x@F>wQ (JY~ޓ\1yPjS&pF)aeJ[.)̩|ۦKMg&l ʋ:j@ӯxQy Mߑ$hQ Tu!K@p yp\M)giyD,$n^ݠ\bϱjkdzh_2R0XNp(" ;.FBǸ$"8/ ȓS&XC?-Zӂ۸hG'a|xmUJZn诞F?/2\xvߨ$\7GZ;fnh;l{Zw?pخg>=yNH1pɡSEÅ:W7gxDH(]SwWd_^}s5R^!.wG* BYC(V p0#;/_cVy*7=|h nɻ@"e ^!FW0 `uh\϶ҳ ._(//X=I-4x>=!0(Y6̳̮B4xc_,l[sca(yQ:)yаvI KdXa`zbNvgAJo;os9tcz9IT?qEqzd|%9R& jpR`I R_(hSU8taL?#Wz d`8Q^t9ӒC9ȡXL;*4 Wv4q05R T/?5Pd9xN^P-ˆzG|V=4qUX0 $F8P۬qev u?$poޥ5VtbQ+->w|BwuON84I",]Ƞ Cg`+K&ÕʡsK#x.&V#21'ʟs¹$ PpJ&oğxϲv;~b9⑧%9YT*6LL~[t?; t>=gv`kt!z/~/w3UbHb\Z"0^o iX)l6X2}anQ vpb&m}^|0q@J(xu^%Lf>Pk2z| sU~0&ZKW5 x |Šy Q| mu'ZWB.*l3n i$ ozcTvH{['R/ ba"/'rDbf>4 @D!֜Qn*bԀ۾r)oaq90d g qISKiy9~yUU  )muv1uB&nț<cf6Nhr1e X"|rʾyeK11,MV*LGOzězk Wj֍#㾀s)+aXFA;t6 e+V@eL{ncc"*;V  MO^^ . pv(/3;=loaQwv\V[K68<ɜbs$OL) `|'|'-xT}q6U{_~]2r/GloG꺣{^9D~v rjV,9%JS3*HGz5.r~R *+,#Lqk~:׼91HZ`湮HJ&a <~"g%=Tj â~Gø8SO]`U/ b3ys&PX UY0 '(g%D4&C'nĈc׼\@]҅/>P6*CMM *nMc)J4i%;ĈZu>4>72zܕ-Ccp[Hcr/Or@2)(ӽ8hZ Ɨ `c92Z;.cXpQk od9O~mg _h5@A"eAGI(o>-I5Aa Xbp-: *_\^$%AC簨 n~ufeRϾwҞ~NNam'Zeܝ)>0}ljƄH89DC}&`iۿ~}?ҞoCNgwb\=B5e /i4hPᮕ0 'EU!h>aBL7d릶sL0s߁I}XU=j|zrz1;{#o+ƱI"LJVb/Q_v}C> 3P9rN4C&u kFYoF oy)Pa蓖k>9p1mC ;u"201"[uY f|($\dlJȉ$K'W=<]Y%62/08bAraS .j4R~LL*^yE|{p/CCOA:~LLsˣWC[ҢL1ԕ#- d{t6+C_3yHE~P}6| k'cy'̓= s޶I9&/wN{A\&<륽[SOûz¦׸cWy9\$a:H^vX[Xq0n  =&L/d۹,]qʻAC"HId TlylAjábgqIS.F i̞w#>21eD' wžOl8@$?qGdşU 5 TҦ;$,>V~.+\>W¬ '4DQ΄pi#=yz/V ՛ʠMci@0BnYm_U)z58ˡXp/κ mym}|\bQik(awR4">/1=:ְ_d+/=U3% >H]&L@3<`*;Ogb m14KzBH-Ir{64_RB2FJ&v`p''M8B$Vݦi^Lt ȧ2DeWI5|p;E$,uRHo&ʓ0В.(nyZ‘pgEbٕpBg1(Qs8]{nM^y^ 6b.#4 hd복}s 8}1iSOwƣp˻0npwO=tl$`$!~uǡD#+~@+Kɇb?7SW?WXFZ# X+Ns0(+$ރ]EH!jm lk1zR:2IZHu d; 4UAV{hpv 0~6tbrŜІʠD@eC"ruJd.F^ۗ Uxv<C5Γ \Bó5ƼÅ+o;UKno iX4J{b- Z44&S U <ۢ\{I8fmKҗ?NmlB VRU+渂;P:Ci;8Jy?&o(^^l@p_0 BP<{>IG ӾGS rR["Ϻ [OYy$8!M!%4gq,&dc\gL@CL-zx&pp m}m;(LP CDMc`r'_PW$`2U )>QC!ho7&TH7 e v6%0#ʣF8$3mpHˀĽQ%+wֱMʋ$Ā;a,X\IAg@]D!GS#<n}N%HULX)Hmf_:CvR'l GdSe%&mS5`4PZT^w2aeĒ(#O$L0[#mT_/:l2d΂X[QUFLL9ia@sohxS_Xq*NpiΘJ+-_o\xߋa@hFZot MOم\7e}+ o_yelO51}yW01x WeU .S+ߓ^E_Xy9gە: p ퟶ\O[lg`w1/wɓ_[ed%- VWrGgօ:82p d0 #@B=Wy|T*,ڗw3hԭo[H\|_ً! PkŔf&ɂߏ -<|綥- 4SAc7Y}E0"3s0|6'9y}1tz?FZ%1o%^AL'87w\!SwdӺ]lD$$ƥϔ3 Jʞ_;hgN0D XآqW\꿎{^4c"wJiqݓ/HU\+Fۊ'L>sm:odlD:a|}of:m!PNWVF|H'$$B41A o8&,[{K_\oOwmowY;()T %< y願 ܀Fqh2KXn҉2`P^JkӲ}Jiw``"suo#z*"4'wu-׻5%Х=޽" QľAE>(6?J΀ybHYI H; <-3 d6_ V1@vuQ 7i ⁔$7n$PS=X:04P7@x˅)cӍŔ t !b]:4V6Fr?EC\:ՈnpZ@€.͕ ÿI%kUOP0\y ZVG^d^D]J+e"sG$ ĭcGN"\eȶwW m6']w?ye [']CxvM7\y/6LT%9NsZ@5'{f {2lo86_!die_}Wbvb#㲔4J2q-J@ 1*EE4ٍw @TWiYao\`yWʭ{pN/1a% |.oG0E+᧸P '*UҘ; rR!hȷlgu7==W׿r%h/ *U{ݳ 02N58҃,-C@N$"++SD&mDB4Bq ?GFK61Н-hBBgq]OՓ\ Sh1M|ywWPt\j.ޞc*o^GG/rg,u"yWu+6Oވ9 40v-F|O(YxY{ "9W_ܬb2w$,h9 )^JWV1Lj51ʅh7lLfԩRi#Ȕxm@Eq}OlwE.Zת\n]ᘵsx>xG?վ_n'b2RUkg^][rAݕJ$Y6><ڦƁM<Ku68X@_UB[nӷ=Ԗ̖{|K@7( nfO.yv'1*!p*4 }yßiyCAmqo~j՗m\ϤG䗏8f'Pt>VA>zM;h VODiTCmb=h[jaƧL%*L(EJ;gR?E>@B. NXrOD4LJ[L^#ry˒ @&=E_M1!5._?FQ-o![/y Sd$-ᔓLXXNu\?v}8@Re7.]mk֫݀bzǩ&v4_*4Б,jRg5>>eG8etrk" o'7~o{_iO<[mɈW]?:l~|qʂ 5^N! k mreVwGQ 14%#i[ Fή1Ż;֩ib@@KEᚮP&P-K8 )| z&JSʢxܒ:\c$H#!QMwI 淢ΓN Tr=I]뤔_pe<L^ZA5Uxl&$6SX s=ֲjI 6mKM%/^nHd>!/e`Vr/iNȯx7QB94aN2x9b+7=ml &5r#A;&q nxFe Og& L888c nj M6H N{ˌīQMV+#ʟ8ezlΥ,|(d7 @ݏtUJ'$d.z)d6Z/(7E'yʌ|N7rR)Ip+D'UI/-_b7*:w!/A*V~ ,%޸|}ϼ|*dHeo24L4Iɾȏ=OﺯM7ܽqpG~ڳ}md寀j'kOگ>JکE-.(bH8(lc($ 30"m`tjP D[_qc0$i]WRӞAw'ZXF)göZ*Q٩uJ ++z/ ޲ՖچLH4L|nSn%lE;]oJj $-w6- w>?7m󻁁| K堘_ZYnio^r6<^='ByMgL>Zhnu'NL& ?|­{7}>7j4if#1!㒎`By7:-IdwF1w7am.ź:q~}nz*,:Ic%Fs ?;->|[e}1BCM1.?fǁ#[1Iҕ\b8'on({&b _MۥG^ HK}ioOCFF^HgKxbiwˠE6m<֕}+LAKY/qW\BunAFda i7$ξbg祋Shj?ٓmz ƻʲmVovL0Xi907YBn0%me,A/=2a#wp  TY F"͵ӛ΃l%JK|Io&tDExv[8Nsn@𫋵];@f < 贈Cx2U2f?Bv>P`rye!b#c2A_p&jL`wdCBCm9/]2ؾLz+]#!߶{/Q@%Ƕ:! (ÒiX:#NJҮ:l c4 }Xķ{K'Bb'֩wh8}ɽv T907Rܤe'~^9hO>%1:4U3-*ymep:HsT'vX3?jAh3\ 8q!ʩSnvm'qāI&_@3PkfmCͬf rf|Z-g%M6vخaQ@PiSSe֛16Yi]Ai=?0 Ax-P nUmKHBIL|Y ݛ9MZg-,&C|[jYs)eȆž`MLZh}\R SRg+7כ)k^1K0)FuYr`)i,[q/-dG>ʫu:vݾ' D>rԺth#ț'Q1!'A-mNy\GgMW^"vYVpyɉ_&4O>x@#w!_j/7N!'8wم`clQrr*1I @c}z}ﲽfA*.@dM*S ?mqwkV,U|~~8'Lu.?¡6wE1.?JBiz>*Q%N9~ڛO~'޵@|&'Dg?ަƫN#twO>lh^FW8W7q8smPr4M(Np3 ,NlB*-EAo`+$$;Sva̲g$.8SCPh&*99(c4kv'xv ^Ky(Cifvs}|/}:!塄 j8젆)'aԇˊr]*lٺvC#T 'Lb4nM0`51DIĴ)o%<4ibqzA+V@N>Xnh q5l9Ҳ:S0]v_t j@c\i!,MQ|Ȋ>*1e])Je8uex81 #-oH 1(r,S,޾Jz.pl~xqSM>'&jzw ڞ4 S~q[?^O?>;2x:0㚏(}f27H\ bرPHt1+Rt}[ Y88FؾzP < 4FG;mw,ڳ[ӓ FOp/6:Y4fA}#WThS嚪+ Шe6&+eyK֋r ^;Gu59w_^R30JW̨d^=D$~up'J9ċ"M*V]*0 %q˵tF" (,rLX̕+ w*PّdItp;J?uN("!X4,Hj@Z~JqVve8hAA<9>!HA8 @@n")CZ|n˙'*_1/X'*8 :md10ۄ*,k`w.tsaը|X?4&JeYJ2 0)?gu<\-&vC~8ѷFȨt !*ylt$i gekL?2o'Pa%~0*loj;-ldF*r\ԓyFSzKͲ>ۗ`06Б#3"N2P|0=ڝ-E^ne98i?@Nxif`WG޶~c+(Q^( XS>GMRnڹkmC{`>+yT^s(i3("hqJgn T4* 6=0!J(aDRY%e>4 +yY:1!ʬb!e'[՚d{~~>!޷mh 2ҟ^= KgGgY:'+R$idkw"(:I^f_kK1, U%C> GZi+ԓ"SLbB Qwѝ~#9 0p«~DŰfKi|WcAߝ os<(@uG$>>=I)}vv%~6y!Cǐ>*7\-׽%3Qp[ m yF 2q.4G(C9kאj8u7}Iq5d'Fߝ.oU%xoKeH!a0g ˮ;^ivgJ[' B ?h`}h+J=AG^~g =4prҮ\!ώq^px\zU0 pۮ\|z^O܏9BWgG fܼD@2xxT3м>νJE;z(OD\CofWXVr˾Ӭmw 2Yq&= L\ q+uî[6 ś T,S.`:NvyF^; p%꫅c-$/y)j BB^(e(m w mXbRk'U^:ם]#3֛2CIEڎ1zR18m>PXS<;Kmr&Rn ,36kLC̗Luhݯnp }c|Y0xjݻC7ٽ5@ lSv0DJ9BԄ:lg -h3?!91u!clІN4>飛?K2A_ /bN%G'rQ` w }"WɌ !?#1r W|'GV!+߼U ;IB;%F: Oy-f>a|rm\qq [Rt[b*$^ #G뗟ǟ(D/|]Ycj7eGa#H|'#v.+6薂KV:#DLVs3;ŊE uۦ[ t,|!;(Pڻ3r{r@m(auETH?ɋA5cH+LYs'z):کr7џ74G}=pcus#(\vZ|!-<Η*9I}WWaAz#Z>L<X_jĽ>qe=mq,1L(>iAƲ͉ʓFeBA{#U;_[CTvzSbd40yihZz_U꼯EДQo>N]2] K~rQ].<)Xoc~qŠs[yN.dPDh6mvbۭGKUI%e5n&dWɾUf#; NHs%oUg&vN`hμ&U@/xY_ɟKu9 ]͌\Ƒ^R~l9lO/b?8]m2aOApXYpEvCz8}$n(|ö${Tܪt&w&FɬOӎ.*Z0 xE͵2+G s%ݗ y3-}C𞴗{YM>ا~}; %DO7Qr^˽XxfѾpA3:5ʭ "H@8g#Âe/hMWںL@Ղ+?2DyNCj[y9`w=>򉭢IZC K`H?bdFbh‰É4W9AEQxaVڪ*# 9s8]ල Qx 8}Y* Rn;_ O`OQ[?īSU'M?XNttox떽+0P6*7~mk#U_&ʅ8A&+iA=J0UʹS'cHABPmM$S,&H՛)7aj-dXM[ܓa$1Wwezpwx`g|Qov%|t`- l.}i;GAwT'k=tn^."Kqr 3&}UUWF|Pv m|ySP9,^G-r֛| oO& ASpTNԄ{Y>`cLǖ)#H [ /2wl](s%Vq~I;C^ˀ3s$@}Fs2,! }Т'p n+iGڮbD'4H*/t[N[+*d|I@i= {Wbgi o/|_nc7^`8FPy]0>tRδA8CsPzo&*|W|+ |ن_aXW&xTtvA~h$="o)1Q>]Y^cƳe.=Ї[FJѹ0ܬHI\ބg94tXx|Wu G/iU ]N@ŗt`+d_;R0pe Nylk{Bu:k\#.O)K_΍OU^>1GiE"ڑDEXn1+oZԇ nwd,cYxkZ3oea"K]"2I+2{8H*[ _!RV0eT1=[Oఆ8+ n8iCJӉZzg{mXsnl<_o/>0 "8;70Y Awaa;]¦kG QV:ƪ tɀMz-VQ,(>֞hHUpļT-hy6 ?@'ݦU83O-`SYh܂j N-/qhCVS*_ F畧W o?mJu^^v%j(`yJàhd4*~ 4A|r@e$UoFG0NY% "N~(KB%!y/ilSq5IYFcb#\&b}IRIr{Wg$țKy'_0trPO^3lOWGqUh Ur+cWP d3YzmB=c ɋli@d9v<>LD8/B޼WgXHS/ͣ||x3ab4v(c_ЖL3!e_홰'Gi>jOG\~voyY|=e1t{ !8 !ɣ>xO}t.8e3*țT( Bp7΁W* 5z/=-<|Ҿ5ГVO; }vO4e f`uVҥ5Ԡ\"\qa~9#C+Z.Bsn(l dr ;442r'{h ]8|ɉb;h\!Q?TsBBz U.߹INF4,i:~ !bmIWC&.11+Itͪ^8OU m7<X2I[1l!(H`Z ܕ\j@F,7I8䃾2VmfrDVy r9<ϖ/"*ɀ h>͍4_>D i0ŽȨs A&nH*O11ش+u%W^|ʁz7oLBh8Yp͇$E@)e]%O Ky12}wJ'4YeV<-& X gXkzӢ;Xԫ~).&%§OIǣ_e=,Bz$b~qg s* [<d=Ew)/AVNTGFDY93y١Hb0WV+է _{vko^~n:!(Aפ@妄M3_suo<>Qzy:<\80$B(F }v;ng+*ve{([FŊ`:^?ϾpLAZ"G Yܕ.&8O'@~dH[5hCǕSɋ6dQ1Z WF8_/TR d"anjb$ȓà݆j ss`@{)b ~H#=#vRAfEh\m/^ "{xʤwti   `0v F|r(|16|R> tW̎t'=Eѿx>:yl,/ݾ/?OrK/NiK vvW }”63ы]W:/mGntv}2y䫓#J4dEiov8p!iҬ!Y'pm')#o=ʯ2))<] YO7F T0-zzokK\auy/~hq( #3jzjM,ޥ e{B_Ù&;~~zXj~~;ԣ|<+<[ J_XqޗwbQkOZlHfKK*G& ^bJd$xw?Nl`e{FUi\#]Uu5tȣ o9BnƤ_Np`/N$a{z>0_9Ui_1dlƥ(oЈi y'JOe4e2LZBW3&)SO& ˨dBJ4MeL#ϛuQ1P*m^^z/Tny 9+e'AAK4j{)1̶-Ŀ@zM']\mK +T[UJNHHafqQU8RХe)_bpї,tzzK}\!lKd2ʁ+ _pWf5.nVxs⃇y{.Z6Mn/{#N.n - /\!v闩rC8U& 9rкߪpl ~'v 1֝\JRf1:0BWU+Og‰dG8T֙Uh2Z{}w~g:^BKk"$  qXe.Pg҉[vYtf "̵O|2taqZr ||ۮ!m2&Nv;rn AҥQejKrM7h }+Fs81L4~uONX$:?E8JO̴'DcE} ΉpIѓ&Zr,Ws m$~dо#쟳["5-$Q;N&&@ۖ2Zyu֦?˜F7h"nÛtȨ# %ԕN'.; 0v B )9 H,L1*-#k `{߱l}˟GݶQņ$^{GLW$oZqMOTIA?'6U~3):Π&We׮PvI&q[L_5WNMk ?ch aK7ܳLw_%1D#0xHWcTIӐŘ~KGyϯ.5 b3T Ԙ|;r1ox;_ y3,f|'k׬ūqwwy 8pJU$~ |L+Ce16kw\G>2A͗1duÕId%Er} :M.O:"Ki8HKJ77+Ȝ?tPYOIp /BaS_pQVPۣ(8Ȥ@XC'X%5 _C2S31.pF Q҆_^_΍+]$|vٟѵrWC8:-|*cnIZBc$*PoXlX{m1 FK1]IS`H.rRH0rLJ&-#+{ |&8a sV|\t馥LiU ґ:—ݫϷ|nHwCO_3vdC*k]Wڅ+pn%^4rv~z]ii %-_ .׾ܖwթ""b[1x,#J z^j:N;_ڟZFW\+zDO}]w7:k©VAǁ@l:gqt˥^]!<)'$s%Ukq5`|o^pJ . C/%| ԑz]*IZ^z$/KH>1>G_4>T_Zc8 U ;C;yBIszC!ϣo UGqu}JWj3yp0k |ymy/A@۞Lm7(O>*Fbu3)y'oe1,1ImgHjVs@gn8tH'e";=!uq;+J|dtH Y;7u&=)a]`#0ׯyt{s&6"8#?ߜ^jI,# iɑ9`Aғt– =2GY`i_{NT;G{=Oױo:<*7m@ؠ)! car*)6yF JA:s J ߊf֞[o}<êz9mTnZ `9iwZ/lO]f}[/*β~0,~h#,(p+;rCgÉásk7#Бծ0'L*`nX#=%w5xhNJ4^w(ϸiZ+$c<4*t{S[ } qo h޽_="_dPMr9&eʾinWo, .2_L]1}/x YprN$0hu$ɧaI]o!MPٳ-X*WK&vye.Q8g 7ezg;ox7ICOĶiWS rH8g sUV?q_otp%uX:˸w|#Ĕ_qHcg?)H0x/OdU~e#+ Ǝk9@"aXvpu>w oPaCHB;Q`|%C“P 7ߺǙD,L mU !p`*4/r*(( +dѽ ja yZOTKT7)C膦z&Vx eK21`iA\!QV7x'fubEg0kU(*mdH/]Pjxpcf[ I`q@.nպMX8 ]5n2}Ί"qq-uqK{;_Oץ;lR,XY?XJ<>h[FDa(H(Gz/^rR$N'0cWL{c+7-[bLE~cO*[bp&4s9i0W{u,kQXxx#I3JSK}t!)0 ` NDNkg}_ꉰ˖vZL;^:j{5DMP tԛgྦrI_z/y7o >_10ah!v%xd0O-w!aމ)g<_X=ui>}i=eSV~SZAI~(` /j9EP*e>̢wmP'vlX׉6>λް}a}i3xe哼(& WRV.W<~Dz=Ivsg"@iť ϱkgE@j"e+EہGv_9Q6KoD[ܲ/!ߗ,4"YgȨ 0rieЩGs9¸maBJM\=:t2J\Wjzsg"'O5iiήC7BYCs&W#8=csrp[_y9bVTg6?Iƭ|q\k5,h=[p{|1&8:m/w9J!;& =߃i㱏ʼn 't Iжd&ChgYw1HB@& @zti7eg,ߟy߲a36.sEceD` gZF:.|R';U"iK;DNVxˈg q|HӷlpUqIIA`ˢ7a'|w\9 (08Ba0*e}#9:zvfr֣ !NCDqCXe>'ɪG<0~alB 4#bShKI[oc>ƽ-g6 2U⁐y\֣^sX eA!Q<KH z;@2L_^')N_\0:(KT[cDjmHgbq4JA@z /xqdK'?|\dO;yB|Ҡх&s傐.We[bvƊEyX=GNri+9LTV=R(!#0<ǞwUGp#1n}(bPRZUJD( ዋߵE`!YEXuʋ xtǘkLj>vZiYdIhْ@'_ Ί.~ (q Ni[kT[u k/1@An[ Qq8R'YQkЯ;Ր-"In7[J cn^ojն7QO^袢Vk5ޠdE#0 g 4(EQJ4L|0 }37WYMR)Ƀa*ߤ:i$2}#ࢠmҮr 5#_c y80pD0V6r1C&0 VDkەm㊬>WdgtOY1VɶB߆ ?2B~RGeeJy(/Dg{ w#WF]gҧ ?{D/Hwh$z6}b/&q$K_=".nhӢG?ã*L:E10&UN$\0ҍ(鞒.i|\I~Qj0:S|Nvzɓq >:`$jjba12Plv߂E< iWy_dw%tcr0mBSɷH7W"C9ȳ[@|tX69h?ٍ,;X|%թC$PЩ|-/ ?.p4S vͬRB3ʕ`@(Ӕ5.>y7ֳrp6Nj$1ăQg[F7VjhhuO+{J6Ҍ^{E^vY.w}`Vunu܌R1]xYw{H_{}LӜ,\aWWm,r7~Lv Ә!qr!4޵z?|ݑs>ĸ?c\i #j/ \=^H iI?pj9-c%Ⱥ4V) -R>F`d?O` pL ڰ1AL%K[ 0O`s/nw#mNp&o3߾-3M1޴G /B.)t8 8>pBId| C76+}+~wSǿŮsS`h\CdI%#ڤ ))[Mqif0ómZƟz3qE\We 9<* MzSJ<$k৬iwr7o KyBF7e1{5 n 姾}1N `:\νoF&'=rt/}dޮ0>u,K<:ux.($& e'BܚZ_?έ h[-egURǜos".{ݳoDAbg}~=/ HPg'\im\AaVoڜ܅d $b A ,CD+PoZt]EQ ;1'w =0e1<0uPo};1y7F4 ㎏[ܮvU)ףOohcXrojUk{ k5rs+pY k}dBE!㔆*km= erSEIC8fC+0B/ፅl/|rMwKmtd1~=.}aQ Ӭ7s`~&o(̷6 قO0qJ[4&hi 18UҶZ%c 72&HÄN)0oSv t٘["E4AB)傝t B/k7n?aZjYpkғjj|smCkgU8q!ٸ8񗟳J]&8[ӏ^i$]ZÄ&Ls $D =YP0TYCu4#)#- QѠeL~[̼ 9ػv]}托 bm !,KPb̺ucLOǒnR%[AHݧ<2m茸㸄YY20P`(a$NJn$(z=UT⚨0>F{>$&J7~/v'9&(w3oe;/]8B Mk AƨBjcmϪ')#,z>o8 'j}YAk5F9Q. ]d?Ix\S_ҧ.OK(FBc( |h(+ھg$d@~h%(oi i VsWۜշ{W޴#TE (c9즴۝w8y%/򕾶Jd##|4R~PGsx֌'[ɳ2|LL"vzW ;aP~ҟ‚Oh=G7:ܞ^@ognM~W;ài1X0WUy3W{|ᜥ9ICXMY39Rm^ "_}bX5o#l~I$r=jz'>wKN*!mhwH^[n$—i_o!Ĭ$-!ѿC LtIy9 ,Xgp{-iƲkl>p`_l ܤw}tB 4p"M(Jĭ#ۛ۳}nf0k,Eeۅ_[2@IM5+ JK2gInzʥ< \e(< |Y^$#~rJ!Tq]YUOL ph c]4zq <'QI _[gQM-چ׎us {=Ȫ#W^2b0ĕR6hM/ 5L<&ט08Y̳~ݐAK&sHrXFO pخ"y[~&O^]c" 0q8X#hAnI n,FO# OZ^H%]$NPEy6[#^kXLYbwV!7ܹQ >XPQ_N2 =o _Ą7CR*jɢLvzӻ97%}W!o~h-ojs&D ^{vi0 n&[֑N+ x_+s(ws{i 9+阏~6]']ى{|a,xV#k֕!S-cs/jAco02cbXJߪdk[s;gڿkۗJoG˫D=txxG|[U^Z ҕ)B2qx?JBGvE珈Cy N#&Ux@-,XxFLB$)7Нƒaҭv pCNv1xrnulTjZ%CX(ԙHK(:UDI%_ͭ◖Fp4+VjS}ZԐ0d[Sܦ`U0[TEB)I"(&l:,x E j;XWip gUFBߡuZ3h\Xq}a{a $(LvP/iP| ~ꮚ§:ാZQN=jq%)7Za}x.zfE+OzMa.8f=BzlnnPT`TpIʂN|}5yh^쎂r$r2h_J.tBFv-ȋcg"?oį>+M5X2ÚbWVSO۩C'/5+~ȍw ¯)gV1d!od+cu0 eeYqOz뿢QdډAGe EHwǘy3]/K(>mkoѵM ATu?醃>n[FVXNW*/q>1kR R+_Q?z#hK¶ּU*7_a'# _fHH`9zYH簨BNO;.ܐnc0B<LK"&#QwJT s[gyx@Xgy\-"Q?oUG,rPi *[z o4h{z{e{֍T pX:D$r8WPUp8$J|/^?e{ߛy/Z-֔lXzӒ0#lYBJM)LaKY_J0bۛZ+k˗ ]IUc 0765}t _?@O@d#;[2 cǸH+| 8!:a\ł7/0ePH*|N'}'mDxEn@dbv$-4|̤uK”HWTG 't5׃<s\yֱ⎌x4(/S[Ǡ|I1tQA:/T-;VȄ4- ܇_]+}!#Q=?|WhZCk/)pf89$GW~c?˰ l4Γě[pBJy'*e2=,O'-D\QkIaLDUP/.DK[txYIG~*K01*D7m9`7 E7ۿv}c?.`2b0Vy/«RfdDuM@GqL_zy~! T,d%q4*2'X0L&yڠ_9Ê\hs kz`;!Y>qfbAhV +2~ZI'}b~qx̖zUpi]*O\l}PN:h^+-"+( 7殈Ps@ ^`r"4bBy\C]M|EYVרk7cpj. No7gAZ\p38StJc&6 B/MzM@ZF`㊱qWY){P,xȗT_'nN2Ldm_ gK\ (]SnHo_G;*Dy,_wDi{f$*Qv$Ɖ@1C68$@zoA0Ҍ׊Ng>εaDIo)k7cx>g:hXH#1=H~NWE%3е_u:2 tflbDcr૵kR%EZіZ-Nb>?9tw7B 6K Ψ6&,rGh lb&T&=Xk7]xZ;Z;jo>-R&.H r$I pJfû_㢈is H(/]etuo_ ,*/5Aa/*J CMKNx>cƘd C>jG;FRMw n <:Uo:&#&fBy5[u+ oU#BXQGy];.}t:lϜjŠgQ)ZR^$h Me@XSO)]N ?ɭv qY*~W A c4ۮ`{POq…g_HxU_=M`2fOL?֮C6lm׺ / j\U/FIf!h0yD:a#nԣ ĈR=w gjH a1w34$!嫊>׽w|IJ?5m3' ݸP8zm]I~Zt>yc$ESm +}M~NT+&[OPf@x&*uiD{íaA {|Nn/.4] ?ʷ.I cw+ Fo#*\d3YUΚ3&-ic}mvwÉג{tRkNƅx'L@!m%n9zԩ;jJ]mwqd;ϓO8l/ TX;I GhÈ:rb,RriĶa253e L"ɇ8);4o?6]xƼ0qFQw18 XҶ\ r3%6^<(NN$< w{6_ڇ}먓O [)Zֆ1_i1$3 ^Ʒ^8rp'G^ T*PeR[N+3 gU4Dď+*m70eCuBH#0O_r;8-4Pd^]nR"F#S*9&#d0;kډ7Yr4-O|=OMt],@ F ~BlACӑ N4Os SO-ڿgڅ _>ەQz!;UVҝɈKtJZ\M 6*Pi4MK"OEy^lEwt{>p^X1'O?N2ºj6V[?˟_z3kmZ BVbl^EܱVPG`kb2Or%?vM=dɟ4}b>)eO@:s*+ j-?*YNCO1ƈ&qYw Gr&e4> 7uzרYfzt'(ي.荞F +<̻g_& Ó1Efm~@Ì|ϯ)Bo͂3y踰K/7(|{ ЁgO;% H'-W}.gAWc.rWi(y@dgcXSTY@3Ls} w'ෟ?l{zoZDq)KKKo_ n(ҒWe,8~-:u1]$#l&x*3##/S[_)OBQ6+J9VYT[OI@J^eeˍ"D.TZ |X2e{Eo8+7QG~2+GDJ  M|g IT;Ψ=)!2`\YGa[?~Ĕ8'gth0x/9*B)J峰(8PDO Rt Όf{f}[7Y؀Ciɀv̫ \JQ(DҤ: OؠyDVlg_}dkghyw]B[B@ 8ii}]xA LybГf+de-+J%BmI^p${7LCkyJ'' Z8hML]I2uil HdRWn#ox'zсjDT">,rU>N`MQ!?k ˅seS`Flhm;bǭwwR6se3.qMwٛ?ecȥm5@"(k} ^#rqdokx'kaw}YþK9#?M7P^ H mM[-Hqx]xG:N1'*XSo?@`q OpyJ~pp-J$w( ]GtSHRLOx)򓒺Sgbplfz󷴷Yn4wNtG,;KI;eBo4ޅ==&Jy%bM#O?"~%wO8[+D~Jj# 9va^7;:#lʗBq-Q̀j{|JAnIAlmL,گmemhZ{Eݥ$OD@^V1Rm ইG֕,hڐx_.EHl34#}=иv8DShbZY|Jf'H|UÉQ&$W N4 տ\2 d`c-jY =U_;aP>\}[[7.C~Iw,\XG~L` J9&jP~~DS.O@vr:lϥFzH#pN^;NbM1i֓4Z3]$3 0E9hR& fm+d%LSxՃ#ĖKNziD:ħ vnz죟j/<ƨfݬ m;(lQw*G:U S0p"(ö9YO|e/k;䔊CWYucY9gQιQPYD p`qb&ӞMĕ`M4u?@k S (>uGHȃ+e'0 JOQ^]ڙ#SOw,ҏnRG_kn:|`z%*^m6ʰPO6RLȤhsy.a4syO%tNEcP(9HYLM;tue˗᪪=IU#Hi)پ]к#Zu QXJ*4\!7! 7&H<У"W}e*r%h&rp]RN-V\8$+rРnReő9*s_%>Q9}NGax`1'5=#l750:W%a|Z9p#,nx?7]ſW"p H(#^ꌫIgM䜘۷>zJ!TN? goRBI|sjRi^l<#gK6Lp9Rc(̩U$,2=WlD?/Lk8YCcocs$Jy2LD52GP`=UJVE H(f-$SNXtRcCrBBXyK!+-(Nݽ~{X;sm ?عloK9*d;'@eNZ8 |EVpkIaI:ظp~ηNmNU㭒1:/7]ݙOܜO(,:93A5̟=.}`u34|—lӆNP)yVd@W<9*ܛWAp@ƧŊ(\J&٤=ue}d{Zx)m?bF./t]ɫK;K.Pi7kO7ܶ ݀'Fj&*rB_)7]qK>j\!׻NӘeFJ:U%AҳW>КU4[,7`M7&„V}3yg/?2~ʉ<~2soo7BP貪hvBۧ>^`Jum-o0&kS*N6vD\O'+sՍv٦jTWێ&U޸eDߴœʅI >y__ˎBrBՒ)l=yy-#ԓ} rw[{Y* Ltҗ8a8sn BɑN/ W ~bCOgV =cYUfH˥9ʈ : 弙riH!C>t$rK~9x GNeVB>H. GaRіsYGAS\rqg^J9#DtiH着: J`O*0NC{5NZJI9XL=wGYTV%+/T\;YV^0q/4`mUDIz ތvn LR8<+.)NqqKgzk紝|I^oTy  dO?^L׃)OdC^{@3s?noX]Ծkon籊;XE1C1[vVEg֤2Y{rrSZ29p21'8iI&"g*ĿzHevLu@@2 ywҡLQQ,O ).H#2g)fj ;[{k/,ۉmaHtTUi3ji#8'@O6'˰& &#P Uzt5> 82@1V$Iʟ  ct lDLMj>9GzpJ b7b4w:/hO="EӨl6kۧ7Fv/ ˟vY| -$Wt]q(52b )68Eט|q+P-sIsnl'ۣ&I :WOZAv`&53A릡9p3(Fӫ"^j7Y=.A 8 [ƿ*opno;v gp2)-#j?C9p*lF+YMyWk'.2!xz=z{Lv))<|QbB<^6wVPӨо9 =8KvdB*,<;s4భddEG~a.vGAԸ' 3 "NYQٗ$-G$I^gȷT)1h^E+ k8wOxqa:呧$G>A͛f^k|pz{󝇬y)Nޚ' D'8|Qz2RSy9!raˑJ L+OXDt2ܞJFZK9O2'c,U%+1ٰN_"/yV+: XSFLKHJ03?:/'pD𓌔>Mʹ#ojҡn\/l;JC>y/@)h%ϸL*y0=zS&yS7َ"[i>CIk7_%+ߋE\q)psk)aoX('B& oY%`!^F6#'u=U_]w[SO=Cp| @`XMtFhp|lN'nl)eUL9 u~ʺ'l_oqy_fVAʟuGe+6dIsy'7bˏ?hdAY3!SЎK*rk\2Md{J̇>>>̾=~_ٱ'Eπki/hsV4fq\IpIW`H+^'}tpiW4P:˦Ʉf(sApC,4|w%޶s9]>qo<O=5nN998.!|Ĵ\i[/Y\S'*UH*bpʋܳM+<GYP%l.0C?yk{|魭қo|mgz/,ԙN ƌ|B ~ڙhH>|?kH^9vⒿN{[$JP& MΩ*QGu |f1RbO'%WJ|l@^v}L}2"$G51>܃c<}'*kgюEN-Rv!-Ib,x9]e>^31QWh(:|Eh$Xe'bk-CtYڨlCx\5s{( ֞"D* n:SvfۆS36 .*db_ʔFn58xF܌W7q؜OW><9=G-? :)iNF;no@NG0(P3vsjg^p5Ǎttc}p\Rhb's@cCYȘ|vɓ}~sZ_P2d+;X<#ӅyL ڋScuwkvkk|o9_{{ے9P&|ʳ\I'6@=tLyĐINjAdy4 T`8N5{$ J܆$frGƯ.r|0>t}1r_cw>j vlwy.6.3el*-LkCFۼ?pS>9*V+VkQ,o9-NyڏH)P>\9≰XcHRȘC/kid'>j|>\G)9q:X.T⤾MO|Б'a<c'tܹ;j:wwx&H-޸s:njqp0z:N,<7h(G8“)>DIp!zںϡ!!M-Ajh^vһ^rv4 V;4n|X h9߽1>xѧwƇ9O^O_v-|8)_`LsDt=vҘ7Nyck&~cBu,fXKo}$E@񵓧D.h dV)%CP% ׾ժ-x2oyIH1'J@*QC}`Wmi0uU:e} ]*'Rv页ScdE~.}QwҖ܊2 ܙH8;&_%U4mX?ƒ'VbG'#1hN| ܠսC | `B?;]%V|V{&8v0:TC? {+_~Ipف +[W̯{|84ŋC&Lj"GȐs̈R N,[6بnjBSp{UL^"2mLy8 ٔT*X^#8V礛39Ul=(TJKf.O ) 4Lf5K-w|=Nq`g;9wDߺ?Ɲc-qZ?PXL,UKcbCBS# 86Dyk.xX8"w0hx~FwQmvl\U5^O_;ׄy|䉱b&S*oO. )U$ Ġ鶕KTv+}KnYK#^r3qe<9;8֘:։r}PVZ1 &O)QA+|frPFBİP4:ʐɟ$e! DZ@{TJDF,ڕH©2@w 5(=@ؓ6tǷܵLx,}'9Ov%rrEw>3c//8:A4m7K/m^3YRvu`!pY 10@ B) \}h'__ӳ@iPCxVa*=/a$_ ֯"渫Z:>!kwǟ'Ǜ KG{9A5vZ&WO j8A6=iUW8eKWle&MKĉ )("l1!Sy&D$/ř'v d9(/bZ:i8>?~m^?;~]4tӸMK F[(x8>O&ӓY/9X 1Տu54x:F 젶yS: Cnؚ:|p*{C|exŸS-O+fp+ƟWAY\#w c@,hmZ IU\ϻ ~=qL;jF %Z  mos*׏dS y"2.ŧ$%TEo)C?sh2%1ci,m,p̖lR^6Pu Ta|\ l,ctK-DC%b%Z{P>^'%{oo팏;q;MYK" a`CDNG *?4w9XTU!1]A &ĕah~\Ba,ma1?ڄAϤӄ]J¦:o{h˒!U/ A|K@ֺ1H`Lκ1saΥ<$Hi}e=:ŏZd5 2SLUS3jD8u@ 2 ؞վ|Sɢ"uf1} TO >?aGڎds0~>&%c0$D7r2)aMٰpзΖ/I~ 2+2|mrM(ADsAR80`Rb/:G".S8#ŨdUu%\aP˲ hK>a:9yWm"m jG[V-rָ/ٶƔ fC}^U|w+`nΩ_[>R-sbX8B.6TEPmUQ 늧u 6ԥ9^8m@$:J`8vtp~Y8{kl7<4tgtti>TD5/~x͡;"&&[E%'AMEҝR G;;M|Ixwj74Pmh2mxE5BR}8*ҐƗs]$vUb ?q9C=bWJ1JyS֖<ȤT\I6&`2fs> I ~Ķפti3}Ү_iѥ`ؾeկ,w !4r^aGl/fVB9nƬCe(읿/40}7%CY;Ŝڳ9.$2# qG)GrMl2 Ė9 vw<1SذQةn㌗: TCg#Ҧuo0u܀ud? nB'0p*||5,d3 `6M4 R8}ͺm˶ۊp$Ad~KHNCpM[A{JpW]aaa]&H9.HqL>Wn"H e.0)7I_Nvdc2# Sƞ6wV!o6(㲫Ey/ (h9$bpe@S23c61웖őI@]4 eg;I8`!qW=O}R%AVl*KUe6HÖ] fl{d!\a_,d7F݁8 AFԳSRuh!I~|]H*րϠ)ćv戆X Jbs/qa*[*DWd߁gJѶB[\u⦌|mu\q^MLMSO17\?o|sc4 6:Yli$3L8 &}dbȤU@MTinyЏݓϝ'}n.}x- :uݚ!AL]۾ |>,CYVz}|N[61!{E/`8bj+9aePYOPe$i;4מf{-قG=g#tJ _ELZ/-)D#8,! 邶=T6%+[^26c',ڶP9M]h9NmnԸ܎YL|#$6Q叟"8yo՜y 0BsE\C:6bV]3I q\mSODSxqjh.%α@>] M]ߓ?/+O>' ޷ W>?^σܱծ'_kRd"6 ,{Bn%"?WZpG(g620<`|֯|`~v} j/@b1B6vk:<iE6A\.y(TE3.@m7ǐ+.#eB~A,P,}<=F/(5΂h"x%<T;H,m=2dc):Yix=9~?Ʈ#Ϋާp[K#W!sn}xJbHAd^SaiD^(FTTi?sHץ'zuo=7Ԅs[9Mt? (z_ pE/9ܦ13kΛs7p럫W~c .ĄS&C;ǯwO~?sy| ݣa%;8[ &F#RmP3Km.j/0p(ri=ba؆|#soi9`rN*nl DL9AО)뙺_E63օJs?ejiM96RjC| mV?=!ˮ~fI`&{9] x&j/4MƔCq(s\:>&IcvmnV YC<9>Z;m s3]5|$D|k""sco{g.*]2שC܇;3}]׉5O'|7M|Ƈul"wr&w˯ 밥E!3 ?CtG]dރ'n.hE0E\ d\S. qa pM<+_Hw`l9:nigßp)aha_YY.M:ZȬ_X4MIk)tHZrf{Eg}*J(YYQ7hPݖ LLK 6KF-X&BiO [vy蟓l϶'Bg\`eo >xBsnKǓ |ބ&'oaӅI[frJa,vtU`O#S3tL)|#^ œdt{>&Ƣ:Vok2;nd`+ DžDvpN=6&}0y{JyC;e4||G>CX4kpώ= Dj Ddnht55Z_Þ~{!wSw<}nc%Xy^]? Mrx< 1)8eTP&I%}8 2Nʶ`ׯqpkB~;7ǃKW G㟾0] HqW)?ǥ)WT$.(2,Vm81wIĵd1zDf GFqCniS!  ]p!lNއU2N]% cqAr]`M' [%91[fb!CYW$ $`x|f:B'}]CKyL◁)3Eb6vs|lik~ &Q6XG%y?_L*>v=Ǎ]x(A֪ ,׾*F;xn< @,@&%b1>Xhk|x_G frh@xΤ?-w% ^ n>xK}1}p @:Z(/٨XWܡ&A]u碑? ~3{{s^N j/8q9"ScAZH waVCd'SIZ*-')n쑱@π`bȨ ˖QqWEV86БGWi$ ahY6 Aߢ;4<=KvgG$eΗ5~)ei`Rr:ǎᲣ14V=\)>]d  ߅V:8S^4MbT[iyx~KOy\[4 ׸W`&}:" Xn+ 7O^xg-A ָ`/gƶ'4jSY CG<}ewhpτwo:- x W3 ;dw{9҄:9?¶>;=ܭcC 'vߎ@ wt~W)_f%]UŌ~FU8.lB*-YbDBp`C-pBCKT,J**(s02(I{xg m@fIL*Sre&Ѧ%}+gyVH\0W”"8,8snQ68~KDbôҧ},K_C "ёhLeLծ`ig! {㯾z}`U>TL*′r)] پɞy ȝgxE- ?{ɵqHmMEǢl[lwy=|{뤸>Ot%:#!Wjv-gɹ۔ h鼠)wڒ,ԉ-؎Tg.TN""%䓸|B+]Fu_[~G3?4v/X8jh/ѤQ[tsHK. pu:u8^o*b33Юy{ /''ɝc[~[ɖ&bl쌽G.xu/?C}/tP8:˄.i@y0y P UprR/O$P~g;%?+Ix1 7XD")ySw,U1:N 70TL۬#LnB/YBh_ nRw6A>[D۝փF~PET!&m,<mv>C-4c+NBJ >1ԓ>P@b9 шҤbO[(b|Q.#3ANeelÄ(=B-d1 ԉҊ@$n)\}[SM@ ==;?ƃ׾?[޸ Tg{c;OU|cQ ?;\]SZ pտk/DC"~Nȃ_ $$©qqp3n_cCO*? ztR F+" *!O`ȃ7Ll*!'% ڮd8yE1d t.eo fL364 ln؍u)at"ނCo͢跜/OV3_Ӿaa6̤)3㌎(CK|]Nu,bK+Y.)%969ǀY_1&lՓLdD;8;6m׭0c{@( T^X|])ׁo9k??N=5*6jnE _4:t3@d‡aF+5+BhH|ewߺ0n폋/'o ρv4ɫp;x8y'~ow; wǞG.{QW~{ǧ㇟?#/^,bxДUicKdaf?mENfUg"j\3`a);x* 2>PXLT%FxG3y.X[cׇ |g9eTB:> 5L"ÂS6!yQHY1@4}IKhmd(%Qa#͋׏se":uo7h% Y%g B=/WdFłmxhѣL~ BbhU>FoO$*b3KxU8Nx}z`] /Krhd4B0M0}DMQ ГaE!'&_РEsWK> ϼ=^W;ZI-P8:ȱDrqrW"coC - _5Pܵq8VWƿ/xZsʝC}LqMPԏP`)ӎ6h l 8N R5{\,VxX _ih;A mZT`k!T>qÅLsV\5ha&Yhu qQ<@xp_`[[;vlltؿh =N5h]+}8'l/O~=}~k/{D~)YHYi#Ath}RHN'W:2nE sNh<ͣM  xDVpߪw.y|UOҒsM7O 5m`F3 Ӟ3Q”ؔx$$Uޮ't.Tf%)Z2/@gd6hظf3وOn#/^rb޶*v ޷32'8Cx ?~zƗ>熸 z NO E W4<|Fh"ګvL$]?ׂWb?ݞ=M,.G*W{ʏw9x0W5_3.ѫcxyk<ug\BX_ /ˋDEA#~ԜPHk g?E ?<jw  ,iJyK"~'mcF?r9PƩ?߀M:@#rPVC(NM*FMN m! &;uXUb%祵݁ Cy!X:!ggEjLY$l״n+!LLNDnE(GTOY+}(Uȋq^dCEH!A&/(rO]e ھVFL]q\S XB#P|h2!?<^/NßV&[/wNN @ 8RiѰ%%'-Sc(O;0ɊɤO[Dtlfߒ6:rRXUxw Eх# n""$(u=S$6cu4id/ٮcɒf_y[lr^4,cp&I`9H[|-,WBi `:C5e6;p~y%E]kc)i'I)04aZw:%`R599V, "lV%K\j3=z}JłJǔo IɄLsX%UؠS<:T ~R,I4J#N2b;OG!MO~k.+_oK.z^5eO:@?Fc{t$Li_ߐ:^l/@,|v6,wWт$7F Z"1ڶBMsʨ%b(Hs>ZR*ҔEfM[󎲆wk/mmQV2OAyN ͢ ˰m2je()>R6g3" p)6 *O~?lgZ> IߦlzhҙMӸQUB`RMe1҉Ko;9ןCO~"%A,]jcbsAW uX+qdՄUjL@h3N>݌7u :G9qdįƮ&y~ƽ |H,7`}+6 J&Pe HKkM]aEum] 4VҸUfd$6 0R4e?uf=ne=sC۟_^׺Z6\v_jk4Ftc]%Wbiݦ$)n.^0x% sSadc̰m#$-LT~.OY3^a([AT2$#0 qdL}y;d<ǥ' XB8wk_7%7歝aڜy/h`bTN[2 Ce _?{yp%َ/Jt+cGx UJ=X}&6m gi/)*`lݔQ3x@:'#|B ye,,>la ? V9F&wstq-5՟c &3K-mBFf`'呹,C%B B>JHO^Hb8e ysx~ho2 __8>奱aAl _IN!Oә!C1FinyiJ#; 6q^O`v\XViKH` ;/x݁rF%&ޡZ|KYKڣک%_"']Y :^́fy.QWoZaρ;_iتp#艥[W^1e_PRrNŠFVQ- NĢ,n@ }FHJ&y_"*_I)lFg:6AV݊e"k `$ʳQ'd\x7wno f+/Wӡxe~._ә@y^Zwt^-tBtL1 ,ݟ/#BH}3IDMYjYWEwOʢhGW2LJ6 |8 "r|K!2<ݜm!8¦S`Bc[4]»riMT&@6Dxywx_x㋟G2s*]:` ؞<FSލm˯y Ym`8ct\x;>5' o3 o{?;nqv1HGYRuL@t~}en䋍mqiwwfJ)Pf@(GC9D,=;VEMm: Ɲͨ lƌ_ 6ѻ9L "uM N*ؤXl򑴏X qVPռR~\K'9zki(A 9"I03b>ʔ,7Q %_)^Alл f 2%8NaF=eL%M8u'cƉWg ֺ$.19Ji .?o&!F 3/~xVע_wx~e3gy":;/$s/:&tyG  Z x/^d,İ:'idmà cdʘj CSڥCE>Q"F ox4$8[ nPfvV]XƷs.v 9lQ hҚJy[32'A[v# ?3Ifqgp#g)8lYn2c*[QCApF&&e^BP%p02"hMj;$ 1/lgd9D&J((IkY>*|oxN|Kl C&~?+OWum /x<K+s̅gȬT}&xL^dU`_UcN-|&?xCňeoydcjqPPQ&;o3Oe%LvZT&[YsN"KIY9))X Y&2|L'cH㟨e`b6fLuX3)H3'TCq 9ga.DŽgP:OǼ ו>>A? {a]`bw{FIۦ{pK;jfIH1/b {&BN6D9bBs]-\D|HF MQz;ր|a1qCg6oy)_[J6IF0gP=.e1J/8C7ڹNHk~I Oo{y4H MS+'T81JL'|6ds۞UJdAI{1G"dz0^ZKcZێ]UHv,Qz"ϙ! a]v>ŒؽpU ߾9^ o-$Bh{CZ,|F\&X c`VHs%o~Yk*|2X' HV-†JJgm З&ib&NfHm0X[| p-!lr:F-M{#;01N6-BYh^0KƫdL{k]=|P: W"mVNՙv>NŌ,$m2fLbEn!KEߚ:o&ͤOtMO~c K3W0ޕ?EG%CclV_pmrF*R[>t [s^.$ I㝼la#cx蹰X聦kdd(]Ċ|C\% hd4- D+0O=yP$̹TB;2,dȉ@ Ȏ5 Q0dP I т|5f:۬O.N8zלil[T ĄMj]@&S˰}> v/m g  Tf?m}{/'Wxºx #x/7 x/ ^vvh{3zSRCPyXMѤAW/}S~kl mW13϶M>$c/Co-;BX_p ct1uvEd0,(zӾ{Mg(k.lRT:vp MW&)ݤY'>6*Hp}|E ! X&ʃ\'Ti<*wbLJwȨ~20R*:j|N&Ra>'ٻ0<'}& l`qpv_}iڗ 85v| ?7DǙ$a<ځuBuA$ >Yz6<"C3d3,.,!fB3B,LĔ]E4EUYL;R1tP閂*بt+0&KTv) Xu6}-Dι͐nDN60i ɾ ڳ/W ' {ǍW^oqk_$౳MbL̤ #/%z6 @Ϝ","bZͶ`DY>&84aA1vyHu!{i("386w 4"[71j[!ӓCN yRخSA&#>v>#Ǯ&&fΫϝ3Tv|h>l8Iyu^DztR惽cohh+#$IyZ qSWvu7q󵯌~wzK ɢ@xki+,Az34;xM@L(L m]*ad<4d{tMI( ɦ@"g Ol(5#3=?sIi~ܾw!/C}={ qM- ΍7o7i_hQ0v5v:#^yH~PC.hC&==IpPЪL`RVs, j=B7> iO9`rKu$)a7S6"T5T98EIl&Fmf ȳpwQݹϩWn^\0 #mW jcZe1-C`L䠬,8bwr;{{O+O~(|  ߷zMWƭ7^wz}jʄ YlJی=80| mZV=" :lDFk[K$Q bN &T 7wgQY"lLOJ&(;ھT (lagCJ!Y`$p(~:.{M`O6M|U$6NҘI=)eDagR^'zn_qa]-~K|W7_ட@3`GVXCa\@W$-c tN+ ZְwPp"')#e.r@%$0)l0[64gӇ ٖ,3X7Isb6S # hσx=p{HwDVdb<T(6NaL%Gؤ5Y-Yhı ݤlIOGAF;eE4QJߥ ^`b 5.aYϐDd3#qGysˣ5S Ou LM / ǏL=?;W?;.ig +vXbap֍qh|1Ӌ, kj^ 8^ |00n+1쪤bif )JxVY84WP,IR1li94A/<@t%m8HO8C"JEj/c9˦X:.M)K纵r -Ģ?ߩT^H?pG#M[觉^+c5__D/^~~`]mwo;8x ;oC0`ЋR˜H.bS$OX2ɲCt&Vl )᜴1 >1&"a:@ % ~yAڷ59'XcU&0Y/e@x-7nJYB.bLI[Fu&pb1M _dL={UDI~eMώKW}u~W·) ޳Bܾ1kapth_>qdͤŒ`deC4 W4w(+x+Ivjv_#od${3f& b59L1*]69n "fLHI̵?ۆ6Qf e2BbM%X~\ar~"X8h&tY L!m{q/_<.\yWVx/X} LJ^ @89:wn# \iɝق;x=`3@Lv&6! e9ze<$FPqLBAlRePVe3O( !>Qt9")€u"-L' \7UyMV"|{=\݋WT]? ٿk~8oO.Vxld߿3'G_;.'}Md|I'xzRj]wHAd۶t!XYo$IדLFZ vKEOPӱ/֢bBu\ښ~$-m*0G(U#_Mwv5J]{/kG$IEYa +|gGq?S,n¡Z00a 7v8WID1KR2jbENe `[K b\|7_n0ʢ,  G6eʼ{gwwN~ؕ?Yau 896h8w Ǚ$YTp &~\d0lH[6` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. texinfo to make Texinfo files echo. gettext to make PO message catalogs echo. changes to make an overview over all changed/added/deprecated items echo. xml to make Docutils-native XML files echo. pseudoxml to make pseudoxml-XML files for display purposes echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) %SPHINXBUILD% 2> nul if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ exit /b 1 ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\JPype.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\JPype.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdf" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf cd %BUILDDIR%/.. echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdfja" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf-ja cd %BUILDDIR%/.. echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "texinfo" ( %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo if errorlevel 1 exit /b 1 echo. echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. goto end ) if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale if errorlevel 1 exit /b 1 echo. echo.Build finished. The message catalogs are in %BUILDDIR%/locale. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) if "%1" == "xml" ( %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml if errorlevel 1 exit /b 1 echo. echo.Build finished. The XML files are in %BUILDDIR%/xml. goto end ) if "%1" == "pseudoxml" ( %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml if errorlevel 1 exit /b 1 echo. echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. goto end ) :end jpype-1.3.0/doc/quickguide.py000066400000000000000000000466601405671516700161430ustar00rootroot00000000000000import textwrap footnotes = [] footnotecounter = 1 def section(Title=None, Desc=None): print("%s" % Title) print("-" * len(Title)) if Desc: print("%s" % Desc) print() print("+" + ("-" * 27) + "+" + ("-" * 57) + "+" + ("-" * 57) + "+") print("| %-25s | %-55s | %-55s |" % ("Description", "Java", "Python")) print("+" + ("=" * 27) + "+" + ("=" * 57) + "+" + ("=" * 57) + "+") def endSection(): print() global footnotes, footnotecounter for i in range(0, len(footnotes)): print(" .. [%d] %s" % (i + footnotecounter, footnotes[i])) footnotecounter += len(footnotes) footnotes = [] print() print() def java(s): return """ .. code-block:: java %s """ % s def python(s): return """ .. code-block:: python %s """ % s def generic(s): return """ .. code-block:: %s """ % s def entry(Desc=None, Java=None, Python=None, Notes=None): global footnotes, footnotecounter if not Java: Java = "" if not Python: Python = "None" if Notes: global footnotes if Notes in footnotes: Desc += " [%d]_" % (footnotes.index(Notes) + footnotecounter) else: Desc += " [%d]_" % (len(footnotes) + footnotecounter) footnotes.append(Notes) DescLines = textwrap.wrap(Desc, 25) DescLines.insert(0, "") JavaLines = Java.split("\n") PythonLines = Python.split("\n") while (len(DescLines) > 0 or len(JavaLines) > 0 or len(PythonLines) > 0): if len(DescLines) > 0: print("| %-25s |" % DescLines.pop(0), end="") else: print("| %-25s |" % "", end="") if len(JavaLines) > 0: print(" %-55s |" % JavaLines.pop(0), end="") else: print(" %-55s |" % "", end="") if len(PythonLines) > 0: print(" %-55s |" % PythonLines.pop(0)) else: print(" %-55s |" % "") print("+" + ("-" * 27) + "+" + ("-" * 57) + "+" + ("-" * 57) + "+") ######################################################## print(""" Java QuickStart Guide ===================== This is a quick start guide to using JPype with Java. This guide will show a series of snippets with the corresponding commands in both Java and Python for using JPype. The :doc:`userguide` and :doc:`api` have additional details on the use of the JPype module. JPype uses two factory classes (``JArray`` and ``JClass``) to produce class wrappers which can be used to create all Java objects. These serve as both the base class for the corresponding hierarchy and as the factory to produce new wrappers. Casting operators are used to construct specify types of Java types (``JObject``, ``JString``, ``JBoolean``, ``JByte``, ``JChar``, ``JShort``, ``JInt``, ``JLong``, ``JFloat``, ``JDouble``). Two special classes serve as the base classes for exceptions (``JException``) and interfaces (``JInterface``). There are a small number of support methods to help in controlling the JVM. Lastly, there are a few annotations used to create customized wrappers. For the purpose of this guide, we will assume that the following classes were defined in Java. We will also assume the reader knows enough Java and Python to be dangerous. """) print(""" .. code-block:: java package org.pkg; publc class BaseClass { public void callMember(int i) {} } public class MyClass extends BaseClass { final public static int CONST_FIELD = 1; public static int staticField = 1; public int memberField = 2; int internalField =3; public MyClass() {} public MyClass(int i) {} public static void callStatic(int i) {} public void callMember(int i) {} // Python name conflict public void pass() {} public void throwsException() throws java.lang.Exception {} // Overloaded methods public void call(int i) {} public void call(double d) {} } """) ##################################################################################### section("Starting JPype", """ The hardest thing about using JPype is getting the jars loaded into the JVM. Java is curiously unfriendly about reporting problems when it is unable to find a jar. Instead, it will be reported as an ``ImportError`` in Python. These patterns will help debug problems with jar loading. Once the JVM is started Java packages that are within a top level domain (TLD) are exposed as Python modules allowing Java to be treated as part of Python. """ ) entry("Start Java Virtual Machine (JVM)", None, """ .. code-block:: python # Import module import jpype # Enable Java imports import jpype.imports # Pull in types from jpype.types import * # Launch the JVM jpype.startJVM() """) entry("Start Java Virtual Machine (JVM) with a classpath", None, """ .. code-block:: python # Launch the JVM jpype.startJVM(classpath = ['jars/*']) """) entry("Import default Java namespace", None, python("import java.lang"), "All ``java.lang.*`` classes are available.") entry("Add a set of jars from a directory", None, python('jpype.addClassPath("/my/path/*")'), "Must happen prior to starting the JVM") entry("Add a specific jar to the classpath", None, python("jpype.addClassPath('/my/path/myJar.jar')"), "Must happen prior to starting the JVM") entry("Print JVM CLASSPATH", None, """ .. code-block:: python from java.lang import System print(System.getProperty("java.class.path")) """, "After JVM is started") endSection() ##################################################################################### section("Classes/Objects", """ Java classes are presented wherever possible similar to Python classes. The only major difference is that Java classes and objects are closed and cannot be modified. As Java is strongly typed, casting operators are used to select specific overloads when calling methods. Classes are either imported using a module, loaded using ``JPackage`` or loaded with the ``JClass`` factory. """) # Importing entry("Import a class", java("import org.pkg.MyClass"), python("from org.pkg import MyClass"), "This will report an error if the class is not found.") entry("Import a class and rename", None, python("from org.pkg import MyClass as OurClass"), "This will report an error if the class is not found.") entry("Import multiple classes from a package", None, python("from org.pkg import MyClass, AnotherClass"), "This will report an error if the classes are not found.") entry("Import a java package for long name access", None, python("import org.pkg"), "Does not report errors if the package is invalid.") entry("Import a class static", java("import org.pkg.MyClass.CONST_FIELD"), python("from org.pkg.MyClass import CONST_FIELD"), 'Constants, static fields, and static methods can be imported.') entry("Import a class without tld", java("import zippy.NonStandard"), python("NonStandard = JClass('zippy.NonStandard')"), "``JClass`` loads any class by name including inner classes.") # Construction entry("Construct an object", java("MyClass myObject = new MyClass(1);"), python("myObject = MyClass(1)")) entry("Constructing a class with full class name", None, """ .. code-block:: python import org.pkg myObject = org.pkg.MyClass(args) """) # Fields entry("Get a static field", java("int var = MyClass.staticField;"), python("var = MyClass.staticField")) entry("Get a member field", java("int var = myObject.memberField;"), python("var = myObject.memberField")) entry("Set a static field", java("MyClass.staticField = 2;"), python("MyClass.staticField = 2"), "This produces an error for final fields.") entry("Set a member field", java("myObject.memberField = 2;"), python("myObject.memberField = 2"), "This produces an error for final fields.") # Methods entry("Call a static method", java("MyClass.callStatic(1);"), python("MyClass.callStatic(1)")) entry("Call a member method", java("myObject.callMember(1);"), python("myObject.callMember(1)")) entry("Access member with Python naming conflict", java("myObject.pass()"), python("myObject.pass_()"), "Underscore is added during wrapping.") entry("Checking inheritance", java("if (obj instanceof MyClass) {...}"), python("if (isinstance(obj, MyClass): ...")) entry("Checking if Java class wrapper", None, python("if (isinstance(obj, JClass): ...")) entry("Checking if Java object wrapper", None, python("if (isinstance(obj, JObject): ...")) # Casting entry("Casting to a specific type", java("BaseClass b = (BaseClass)myObject;"), generic("b = (BaseClass) @ myObject"), "Matmul(@) is used as the casting operator.") endSection() ##################################################################################### section("Exceptions", """ Java exceptions extend from Python exceptions and can be dealt with in the same way as Python native exceptions. JException serves as the base class for all Java exceptions. """) entry("Catch an exception", """ .. code-block:: java try { myObject.throwsException(); } catch (java.lang.Exception ex) { ... } """, """ .. code-block:: python try: myObject.throwsException() except java.lang.Exception as ex: ... """) entry("Throw an exception to Java", """ .. code-block:: java throw new java.lang.Exception( "Problem"); """, """ .. code-block:: python raise java.lang.Exception( "Problem") """) entry("Checking if Java exception wrapper", None, python('if (isinstance(obj, JException): ...')) entry("Closeable items", """ .. code-block:: java try (InputStream is = Files.newInputStream(file)) { ... } """, """ .. code-block:: python with Files.newInputStream(file) as is: ... """) endSection() ##################################################################################### section("Primitives", """ Most Python primitives directly map into Java primitives. However, Python does not have the same primitive types, and it is necessary to cast to a specific Java primitive type whenever there are Java overloads that would otherwise be in conflict. Each of the Java types are exposed in JPype (``JBoolean``, ``JByte``, ``JChar``, ``JShort``, ``JInt``, ``JLong``, ``JFloat``, ``JDouble``). """) entry("Casting to hit an overload", java("myObject.call((int)v);"), python("myObject.call(JInt(v))"), "``JInt`` acts as a casting operator") entry("Create a primitive array", java("int[] array = new int[5]"), python("array = JInt[5]")) entry("Create a rectangular primitive array", java("int[][] array = new int[5][10]"), python("array = JInt[5, 10]")) entry("Create an array of arrays", java("int[][] array = new int[5][]"), python("array = JInt[5, :]")) entry("Create an initialized primitive array", java("int[] array = new int[]{1,2,3}"), python("array = JInt[:]([1,2,3])"), "list, sequences, or np.array can be used to initialize.") entry("Create an initialized boxed array", java("Integer[] array = new Integer[]{1,2,3}"), python("array = java.lang.Integer[:]([1,2,3])"), "list, sequences, or np.array can be used to initialize.") entry("Put a specific primitive type on a list", """ .. code-block:: java List myList = new ArrayList<>(); myList.add(1); """, """ .. code-block:: python from java.util import ArrayList myList = ArrayList() myList.add(JInt(1)) """) entry("Boxing a primitive", java("Integer boxed = 1;"), python("boxed = JObject(JInt(1))"), "``JInt`` specifies the prmitive type. ``JObject`` boxes the primitive.") endSection() ##################################################################################### section("Strings", """ Java strings are similar to Python strings. They are both immutable and produce a new string when altered. Most operations can use Java strings in place of Python strings, with minor exceptions as Python strings are not completely duck typed. When comparing or using as dictionary keys, all JString objects should be converted to Python. """) entry("Create a Java string", java('String javaStr = new String("foo");'), python( 'myStr = JString("foo")'), "``JString`` constructs a ``java.lang.String``") entry("Create a Java string from bytes", ''' .. code-block:: java byte[] b; String javaStr = new String(b, "UTF-8"); ''', ''' .. code-block:: python b= b'foo' myStr = JString(b, "UTF-8") ''', "All ``java.lang.String`` constuctors work.") entry("Converting Java string", None, python("str(javaStr)")) entry("Comparing Python and Java strings", None, python( "str(javaStr) == pyString"), "``str()`` converts the object for comparison") entry("Comparing Java strings", java( 'javaStr.equals("foo")'), python('javaStr == "foo"')) entry("Checking if Java string", None, python( "if (isinstance(obj, JString): ...")) endSection() ##################################################################################### section("Arrays", """ Arrays are create using the JArray class factory. They operate like Python lists, but they are fixed in size. """) entry("Create a single dimension array", java("MyClass[] array = new MyClass[5];"), python("array = MyClass[5]")) entry("Create a multi dimension array (old)", java("MyClass[][] array2 = new MyClass[5][];"), python("array2 = JArray(MyClass, 2)(5)")) entry("Create a multi dimension array (new)", java("MyClass[][] array2 = new MyClass[5][];"), python("array2 = MyClass[5,:]")) entry("Access an element", java("array[0] = new MyClass()"), python("array[0] = MyClass()")) entry("Size of an array", java("array.length"), python("len(array)")) entry("Get last element", java("MyClass a = array[array.length];"), python("a = array[-1]")) entry("Slice an array", None, python("a = array[2:5]"), "A Slice is a view and changes will be reflected on original. Slices passed to Java will clone.") entry("Clone an array", java("MyClass[] a = array.clone();"), python("a = array.clone()")) entry("Convert to Python list", None, python("pylist = list(array)")) entry("Iterate elements", """ .. code-block:: java for (MyClass element: array) {...} """, """ .. code-block:: python for element in array: ... """) entry("Checking if java array wrapper", None, python("if (isinstance(obj, JArray): ...")) endSection() ##################################################################################### section("Collections", """ Java standard containers are available and are overloaded with Python syntax where possible to operate in a similar fashion to Python objects. """) entry("Import list type", java("import java.util.ArrayList;"), python("from java.util import ArrayList")) entry("Construct a list", java("List myList=new ArrayList<>();"), python("myList=ArrayList()")) entry("Get length of list", java("int sz = myList.size();"), python("sz = len(myList)")) entry("Get list item", java('Integer i = myList.get(0)'), python('i = myList[0]')) entry("Set list item", java('myList.set(0, 1)'), python('myList[0]=Jint(1)'), "Casting is required to box primitives to the correct type.") entry("Iterate list elements", """ .. code-block:: java for (Integer element: myList) {...} """, """ .. code-block:: python for element in myList: ... """) entry("Import map type", java("import java.util.HashMap;"), python("from java.util import HashMap")) entry("Construct a map", java("Map myMap = new HashMap<>();"), python("myMap = HashMap()")) entry("Get length of map", java("int sz = myMap.size();"), python("sz = len(myMap)")) entry("Get map item", java('Integer i = myMap.get("foo")'), python('i = myMap["foo"]')) entry("Set map item", java('myMap.set("foo", 1)'), python('myMap["foo"] = Jint(1)'), "Casting is required to box primitives to the correct type.") entry("Iterate map entries", """ .. code-block:: java for (Map.Entry e : myMap.entrySet()) {...} """, """ .. code-block:: python for e in myMap.entrySet(): ... """) endSection() ##################################################################################### section("Reflection", """ Java reflection can be used to access operations that are outside the scope of the JPype syntax. This includes calling a specific overload or even accessing private methods and fields. """) entry("Access Java reflection class", java("MyClass.class"), python("MyClass.class_")) entry("Access a private field by name", None, """ .. code-block:: python cls = myObject.class_ field = cls.getDeclaredField( "internalField") field.setAccessible(True) field.get() """, """This is prohibited after Java 8""") entry("Accessing a specific overload", None, """ .. code-block:: python cls = MyClass.class_ cls.getDeclaredMethod("call", JInt) cls.invoke(myObject, JInt(1)) """, "types must be exactly specified.") entry("Convert a ``java.lang.Class`` into Python wrapper", None, """ .. code-block:: python # Something returned a java.lang.Class MyClassJava = getClassMethod() # Convert to it to Python MyClass = JClass(myClassJava) """, "Rarely required unless the class was supplied external such as generics.") entry("Load a class with a external class loader", """ .. code-block:: java ClassLoader cl = new ExternalClassLoader(); Class cls = Class.forName("External", True, cl) """, """ .. code-block:: python cl = ExternalClassLoader() cls = JClass("External", loader=cl) """) entry("Accessing base method implementation", None, """ .. code-block:: python from org.pkg import \\ BaseClass, MyClass myObject = MyClass(1) BaseClass.callMember(myObject, 2) """) endSection() section("Implements and Extension", """ JPype can implement a Java interface by annotating a Python class. Each method that is required must be implemented. JPype does not support extending a class directly in Python. Where it is necessary to exend a Java class, it is required to create a Java extension with an interface for each methods that are to be accessed from Python. """) entry("Implement an interface", """ .. code-block:: java public class PyImpl implements MyInterface { public void call() {...} } """, """ .. code-block:: python @JImplements(MyInterface) class PyImpl(object): @JOverride def call(self): pass """, "") entry("Extending classes", None, None, """Support for use of Python function as Java 8 lambda is WIP.""") entry("Lambdas", java('DoubleUnaryOperator u = (p->p*2);'), generic('u=DoubleUnaryOperator@(lambda x: x*2)'), 'Any Java functional interface can take a lambda or callable.') endSection() print( """ Don't like the formatting? Feel the guide is missing something? Submit a pull request at the project page. """) jpype-1.3.0/doc/quickguide.rst000066400000000000000000002415671405671516700163260ustar00rootroot00000000000000 Java QuickStart Guide ===================== This is a quick start guide to using JPype with Java. This guide will show a series of snippets with the corresponding commands in both Java and Python for using JPype. The :doc:`userguide` and :doc:`api` have additional details on the use of the JPype module. JPype uses two factory classes (``JArray`` and ``JClass``) to produce class wrappers which can be used to create all Java objects. These serve as both the base class for the corresponding hierarchy and as the factory to produce new wrappers. Casting operators are used to construct specify types of Java types (``JObject``, ``JString``, ``JBoolean``, ``JByte``, ``JChar``, ``JShort``, ``JInt``, ``JLong``, ``JFloat``, ``JDouble``). Two special classes serve as the base classes for exceptions (``JException``) and interfaces (``JInterface``). There are a small number of support methods to help in controlling the JVM. Lastly, there are a few annotations used to create customized wrappers. For the purpose of this guide, we will assume that the following classes were defined in Java. We will also assume the reader knows enough Java and Python to be dangerous. .. code-block:: java package org.pkg; public class BaseClass { public void callMember(int i) {} } public class MyClass extends BaseClass { final public static int CONST_FIELD = 1; public static int staticField = 1; public int memberField = 2; int internalField =3; public MyClass() {} public MyClass(int i) {} public static void callStatic(int i) {} public void callMember(int i) {} // Python name conflict public void pass() {} public void throwsException() throws java.lang.Exception {} // Overloaded methods public void call(int i) {} public void call(double d) {} } Starting JPype -------------- The hardest thing about using JPype is getting the jars loaded into the JVM. Java is curiously unfriendly about reporting problems when it is unable to find a jar. Instead, it will be reported as an ``ImportError`` in Python. These patterns will help debug problems with jar loading. Once the JVM is started Java packages that are within a top level domain (TLD) are exposed as Python modules allowing Java to be treated as part of Python. +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | Description | Java | Python | +===========================+=========================================================+=========================================================+ | | | | | Start Java Virtual | | .. code-block:: python | | Machine (JVM) | | | | | | # Import module | | | | import jpype | | | | | | | | # Enable Java imports | | | | import jpype.imports | | | | | | | | # Pull in types | | | | from jpype.types import * | | | | | | | | # Launch the JVM | | | | jpype.startJVM() | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Start Java Virtual | | .. code-block:: python | | Machine (JVM) with a | | | | classpath | | # Launch the JVM | | | | jpype.startJVM(classpath = ['jars/*']) | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Import default Java | | .. code-block:: python | | namespace [1]_ | | | | | | import java.lang | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Add a set of jars from a | | .. code-block:: python | | directory [2]_ | | | | | | jpype.addClassPath("/my/path/*") | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Add a specific jar to the | | .. code-block:: python | | classpath [2]_ | | | | | | jpype.addClassPath('/my/path/myJar.jar') | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Print JVM CLASSPATH [3]_ | | .. code-block:: python | | | | | | | | from java.lang import System | | | | print(System.getProperty("java.class.path")) | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ .. [1] All ``java.lang.*`` classes are available. .. [2] Must happen prior to starting the JVM .. [3] After JVM is started Classes/Objects --------------- Java classes are presented wherever possible similar to Python classes. The only major difference is that Java classes and objects are closed and cannot be modified. As Java is strongly typed, casting operators are used to select specific overloads when calling methods. Classes are either imported using a module, loaded using ``JPackage`` or loaded with the ``JClass`` factory. +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | Description | Java | Python | +===========================+=========================================================+=========================================================+ | | | | | Import a class [4]_ | .. code-block:: java | .. code-block:: python | | | | | | | import org.pkg.MyClass | from org.pkg import MyClass | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Import a class and rename | | .. code-block:: python | | [4]_ | | | | | | from org.pkg import MyClass as OurClass | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Import multiple classes | | .. code-block:: python | | from a package [5]_ | | | | | | from org.pkg import MyClass, AnotherClass | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Import a java package for | | .. code-block:: python | | long name access [6]_ | | | | | | import org.pkg | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Import a class static | .. code-block:: java | .. code-block:: python | | [7]_ | | | | | import org.pkg.MyClass.CONST_FIELD | from org.pkg.MyClass import CONST_FIELD | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Import a class without | .. code-block:: java | .. code-block:: python | | tld [8]_ | | | | | import zippy.NonStandard | NonStandard = JClass('zippy.NonStandard') | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Construct an object | .. code-block:: java | .. code-block:: python | | | | | | | MyClass myObject = new MyClass(1); | myObject = MyClass(1) | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Constructing a class with | | .. code-block:: python | | full class name | | | | | | import org.pkg | | | | myObject = org.pkg.MyClass(args) | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Get a static field | .. code-block:: java | .. code-block:: python | | | | | | | int var = MyClass.staticField; | var = MyClass.staticField | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Get a member field | .. code-block:: java | .. code-block:: python | | | | | | | int var = myObject.memberField; | var = myObject.memberField | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Set a static field [9]_ | .. code-block:: java | .. code-block:: python | | | | | | | MyClass.staticField = 2; | MyClass.staticField = 2 | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Set a member field [9]_ | .. code-block:: java | .. code-block:: python | | | | | | | myObject.memberField = 2; | myObject.memberField = 2 | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Call a static method | .. code-block:: java | .. code-block:: python | | | | | | | MyClass.callStatic(1); | MyClass.callStatic(1) | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Call a member method | .. code-block:: java | .. code-block:: python | | | | | | | myObject.callMember(1); | myObject.callMember(1) | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Access member with Python | .. code-block:: java | .. code-block:: python | | naming conflict [10]_ | | | | | myObject.pass() | myObject.pass_() | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Checking inheritance | .. code-block:: java | .. code-block:: python | | | | | | | if (obj instanceof MyClass) {...} | if (isinstance(obj, MyClass): ... | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Checking if Java class | | .. code-block:: python | | wrapper | | | | | | if (isinstance(obj, JClass): ... | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Checking if Java object | | .. code-block:: python | | wrapper | | | | | | if (isinstance(obj, JObject): ... | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Casting to a specific | .. code-block:: java | .. code-block:: | | type [11]_ | | | | | BaseClass b = (BaseClass)myObject; | b = (BaseClass) @ myObject | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ .. [4] This will report an error if the class is not found. .. [5] This will report an error if the classes are not found. .. [6] Does not report errors if the package is invalid. .. [7] Constants, static fields, and static methods can be imported. .. [8] ``JClass`` loads any class by name including inner classes. .. [9] This produces an error for final fields. .. [10] Underscore is added during wrapping. .. [11] Matmul(@) is used as the casting operator. Exceptions ---------- Java exceptions extend from Python exceptions and can be dealt with in the same way as Python native exceptions. JException serves as the base class for all Java exceptions. +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | Description | Java | Python | +===========================+=========================================================+=========================================================+ | | | | | Catch an exception | .. code-block:: java | .. code-block:: python | | | | | | | try { | try: | | | myObject.throwsException(); | myObject.throwsException() | | | } catch (java.lang.Exception ex) | except java.lang.Exception as ex: | | | { ... } | ... | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Throw an exception to | .. code-block:: java | .. code-block:: python | | Java | | | | | throw new java.lang.Exception( | raise java.lang.Exception( | | | "Problem"); | "Problem") | | | | | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Checking if Java | | .. code-block:: python | | exception wrapper | | | | | | if (isinstance(obj, JException): ... | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Closeable items | .. code-block:: java | .. code-block:: python | | | | | | | try (InputStream is | with Files.newInputStream(file) as is: | | | = Files.newInputStream(file)) | ... | | | { ... } | | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ Primitives ---------- Most Python primitives directly map into Java primitives. However, Python does not have the same primitive types, and it is necessary to cast to a specific Java primitive type whenever there are Java overloads that would otherwise be in conflict. Each of the Java types are exposed in JPype (``JBoolean``, ``JByte``, ``JChar``, ``JShort``, ``JInt``, ``JLong``, ``JFloat``, ``JDouble``). +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | Description | Java | Python | +===========================+=========================================================+=========================================================+ | | | | | Casting to hit an | .. code-block:: java | .. code-block:: python | | overload [12]_ | | | | | myObject.call((int)v); | myObject.call(JInt(v)) | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Create a primitive array | .. code-block:: java | .. code-block:: python | | | | | | | int[] array = new int[5] | array = JInt[5] | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Create a rectangular | .. code-block:: java | .. code-block:: python | | primitive array | | | | | int[][] array = new int[5][10] | array = JInt[5, 10] | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Create an array of arrays | .. code-block:: java | .. code-block:: python | | | | | | | int[][] array = new int[5][] | array = JInt[5, :] | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Create an initialized | .. code-block:: java | .. code-block:: python | | primitive array [13]_ | | | | | int[] array = new int[]{1,2,3} | array = JInt[:]([1,2,3]) | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Create an initialized | .. code-block:: java | .. code-block:: python | | boxed array [13]_ | | | | | Integer[] array = new Integer[]{1,2,3} | array = java.lang.Integer[:]([1,2,3]) | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Put a specific primitive | .. code-block:: java | .. code-block:: python | | type on a list | | | | | List myList | from java.util import ArrayList | | | = new ArrayList<>(); | myList = ArrayList() | | | myList.add(1); | myList.add(JInt(1)) | | | | | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Boxing a primitive [14]_ | .. code-block:: java | .. code-block:: python | | | | | | | Integer boxed = 1; | boxed = JObject(JInt(1)) | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ .. [12] ``JInt`` acts as a casting operator .. [13] list, sequences, or np.array can be used to initialize. .. [14] ``JInt`` specifies the prmitive type. ``JObject`` boxes the primitive. Strings ------- Java strings are similar to Python strings. They are both immutable and produce a new string when altered. Most operations can use Java strings in place of Python strings, with minor exceptions as Python strings are not completely duck typed. When comparing or using as dictionary keys, all JString objects should be converted to Python. +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | Description | Java | Python | +===========================+=========================================================+=========================================================+ | | | | | Create a Java string | .. code-block:: java | .. code-block:: python | | [15]_ | | | | | String javaStr = new String("foo"); | myStr = JString("foo") | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Create a Java string from | .. code-block:: java | .. code-block:: python | | bytes [16]_ | | | | | byte[] b; | b= b'foo' | | | String javaStr = new String(b, "UTF-8"); | myStr = JString(b, "UTF-8") | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Converting Java string | | .. code-block:: python | | | | | | | | str(javaStr) | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Comparing Python and Java | | .. code-block:: python | | strings [17]_ | | | | | | str(javaStr) == pyString | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Comparing Java strings | .. code-block:: java | .. code-block:: python | | | | | | | javaStr.equals("foo") | javaStr == "foo" | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Checking if Java string | | .. code-block:: python | | | | | | | | if (isinstance(obj, JString): ... | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ .. [15] ``JString`` constructs a ``java.lang.String`` .. [16] All ``java.lang.String`` constuctors work. .. [17] ``str()`` converts the object for comparison Arrays ------ Arrays are create using the JArray class factory. They operate like Python lists, but they are fixed in size. +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | Description | Java | Python | +===========================+=========================================================+=========================================================+ | | | | | Create a single dimension | .. code-block:: java | .. code-block:: python | | array | | | | | MyClass[] array = new MyClass[5]; | array = MyClass[5] | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Create a multi dimension | .. code-block:: java | .. code-block:: python | | array (old) | | | | | MyClass[][] array2 = new MyClass[5][]; | array2 = JArray(MyClass, 2)(5) | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Create a multi dimension | .. code-block:: java | .. code-block:: python | | array (new) | | | | | MyClass[][] array2 = new MyClass[5][]; | array2 = MyClass[5,:] | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Access an element | .. code-block:: java | .. code-block:: python | | | | | | | array[0] = new MyClass() | array[0] = MyClass() | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Size of an array | .. code-block:: java | .. code-block:: python | | | | | | | array.length | len(array) | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Get last element | .. code-block:: java | .. code-block:: python | | | | | | | MyClass a = array[array.length]; | a = array[-1] | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Slice an array [18]_ | | .. code-block:: python | | | | | | | | a = array[2:5] | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Clone an array | .. code-block:: java | .. code-block:: python | | | | | | | MyClass[] a = array.clone(); | a = array.clone() | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Convert to Python list | | .. code-block:: python | | | | | | | | pylist = list(array) | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Iterate elements | .. code-block:: java | .. code-block:: python | | | | | | | for (MyClass element: array) | for element in array: | | | {...} | ... | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Checking if java array | | .. code-block:: python | | wrapper | | | | | | if (isinstance(obj, JArray): ... | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ .. [18] A Slice is a view and changes will be reflected on original. Slices passed to Java will clone. Collections ----------- Java standard containers are available and are overloaded with Python syntax where possible to operate in a similar fashion to Python objects. +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | Description | Java | Python | +===========================+=========================================================+=========================================================+ | | | | | Import list type | .. code-block:: java | .. code-block:: python | | | | | | | import java.util.ArrayList; | from java.util import ArrayList | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Construct a list | .. code-block:: java | .. code-block:: python | | | | | | | List myList=new ArrayList<>(); | myList=ArrayList() | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Get length of list | .. code-block:: java | .. code-block:: python | | | | | | | int sz = myList.size(); | sz = len(myList) | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Get list item | .. code-block:: java | .. code-block:: python | | | | | | | Integer i = myList.get(0) | i = myList[0] | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Set list item [19]_ | .. code-block:: java | .. code-block:: python | | | | | | | myList.set(0, 1) | myList[0]=Jint(1) | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Iterate list elements | .. code-block:: java | .. code-block:: python | | | | | | | for (Integer element: myList) | for element in myList: | | | {...} | ... | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Import map type | .. code-block:: java | .. code-block:: python | | | | | | | import java.util.HashMap; | from java.util import HashMap | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Construct a map | .. code-block:: java | .. code-block:: python | | | | | | | Map myMap = new HashMap<>(); | myMap = HashMap() | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Get length of map | .. code-block:: java | .. code-block:: python | | | | | | | int sz = myMap.size(); | sz = len(myMap) | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Get map item | .. code-block:: java | .. code-block:: python | | | | | | | Integer i = myMap.get("foo") | i = myMap["foo"] | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Set map item [19]_ | .. code-block:: java | .. code-block:: python | | | | | | | myMap.set("foo", 1) | myMap["foo"] = Jint(1) | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Iterate map entries | .. code-block:: java | .. code-block:: python | | | | | | | for (Map.Entry e | for e in myMap.entrySet(): | | | : myMap.entrySet()) | ... | | | {...} | | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ .. [19] Casting is required to box primitives to the correct type. Reflection ---------- Java reflection can be used to access operations that are outside the scope of the JPype syntax. This includes calling a specific overload or even accessing private methods and fields. +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | Description | Java | Python | +===========================+=========================================================+=========================================================+ | | | | | Access Java reflection | .. code-block:: java | .. code-block:: python | | class | | | | | MyClass.class | MyClass.class_ | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Access a private field by | | .. code-block:: python | | name [20]_ | | | | | | cls = myObject.class_ | | | | field = cls.getDeclaredField( | | | | "internalField") | | | | field.setAccessible(True) | | | | field.get() | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Accessing a specific | | .. code-block:: python | | overload [21]_ | | | | | | cls = MyClass.class_ | | | | cls.getDeclaredMethod("call", JInt) | | | | cls.invoke(myObject, JInt(1)) | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Convert a | | .. code-block:: python | | ``java.lang.Class`` into | | | | Python wrapper [22]_ | | # Something returned a java.lang.Class | | | | MyClassJava = getClassMethod() | | | | | | | | # Convert to it to Python | | | | MyClass = JClass(myClassJava) | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Load a class with a | .. code-block:: java | .. code-block:: python | | external class loader | | | | | ClassLoader cl | cl = ExternalClassLoader() | | | = new ExternalClassLoader(); | cls = JClass("External", loader=cl) | | | Class cls | | | | = Class.forName("External", | | | | True, cl) | | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Accessing base method | | .. code-block:: python | | implementation | | | | | | from org.pkg import \ | | | | BaseClass, MyClass | | | | myObject = MyClass(1) | | | | BaseClass.callMember(myObject, 2) | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ .. [20] This is prohibited after Java 8 .. [21] types must be exactly specified. .. [22] Rarely required unless the class was supplied external such as generics. Implements and Extension ------------------------ JPype can implement a Java interface by annotating a Python class. Each method that is required must be implemented. JPype does not support extending a class directly in Python. Where it is necessary to exend a Java class, it is required to create a Java extension with an interface for each methods that are to be accessed from Python. +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | Description | Java | Python | +===========================+=========================================================+=========================================================+ | | | | | Implement an interface | .. code-block:: java | .. code-block:: python | | | | | | | public class PyImpl | @JImplements(MyInterface) | | | implements MyInterface | class PyImpl(object): | | | { | @JOverride | | | public void call() | def call(self): | | | {...} | pass | | | } | | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | None | | Extending classes [23]_ | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ | | | | | Lambdas [24]_ | .. code-block:: java | .. code-block:: | | | | | | | DoubleUnaryOperator u = (p->p*2); | u=DoubleUnaryOperator@(lambda x: x*2) | | | | | +---------------------------+---------------------------------------------------------+---------------------------------------------------------+ .. [23] Support for use of Python function as Java 8 lambda is WIP. .. [24] Any Java functional interface can take a lambda or callable. Don't like the formatting? Feel the guide is missing something? Submit a pull request at the project page. jpype-1.3.0/doc/release.rst000066400000000000000000000026021405671516700155750ustar00rootroot00000000000000:orphan: Release cycle docs ================== This project uses bump2version See https://medium.com/@williamhayes/versioning-using-bumpversion-4d13c914e9b8 To start a new cycle use: ``bumpversion patch`` To increment the build number during development: ``bumpversion build`` To release: ``bumpversion release`` Full process: (first copy the checklist to an issue) - [ ] Start from the release branch ``git checkout release`` - [ ] Make a new branch for the release cycle ``git checkout -b releases/{version}`` - [ ] Merge the current master with the release ``git pull origin master`` - [ ] Start a release ``bumpversion release`` - [ ] Edit doc/CHANGELOG.rst - [ ] Send the release to be evaluated ``git push`` - [ ] Verify CI on azure - [ ] Manually trigger a ``jpype.release`` on azure If successful, download the artifacts for publication. - [ ] Advance the release pointer ``git checkout release`` ``git merge releases/`` - [ ] Publish the release - Add draft release on github - Attach the artifacts to the release. - [ ] Start master on a new cycle - Use a PR to pull release back to master - ``git checkout master`` - ``git checkout -b cycle`` - ``git merge release`` - ``bumpversion patch`` - Use PR to insert the cycle in master **Last, update this document with any changes in process that were required.** jpype-1.3.0/doc/userguide.rst000066400000000000000000004351211405671516700161570ustar00rootroot00000000000000################## JPype User Guide ################## .. toctree:: :maxdepth: 2 JPype Introduction ****************** JPype is a Python module to provide full access to Java from within Python. Unlike Jython, JPype does not achive this by re-implementing Python, but instead by interfacing both virtual machines at the native level. This shared memory based approach achieves good computing performance, while providing the access to the entirety of CPython and Java libraries. This approach allows direct memory access between the two machines, implementation of Java interfaces in Python, and even use of Java threading. JPype Use Cases =============== Here are three typical reasons to use JPype. - Access to a Java library from a Python program (Python oriented) - Visualization of Java data structures (Java oriented) - Interactive Java and Python development including scientific and mathematical programming. Let's explore each of these options. Case 1: Access to a Java library -------------------------------- Suppose you are a hard core Python programmer. You can easily use lambdas, threading, dictionary hacking, monkey patching, been there, done that. You are hard at work on your latest project but you just need to pip in the database driver for your customers database and you can call it a night. Unfortunately, it appears that your customers database will not connect to the Python database API. The whole thing is custom and the customer isn't going to supply you with a Python version. They did sent you a Java driver for the database but fat lot of good that will do for you. Stumbling through the internet you find a module that says it can natively load Java packages as Python modules. Well, it worth a shot... So first thing the guide says is that you need to install Java and set up a ``JAVA_HOME`` environment variable pointing to the JRE. Then start the JVM with classpath pointed to customers jar file. The customer sent over an example in Java so you just have to port it into Python. .. code-block:: java package com.paying.customer; import com.paying.customer.DataBase public class MyExample { public void main(String[] args) { Database db = new Database("our_records"); try (DatabaseConnection c = db.connect()) { c.runQuery(); while (c.hasRecords()) { Record record = db.nextRecord(); ... } } } } It does not look too horrible to translate. You just need to look past all those pointless type declarations and meaningless braces. Once you do, you can glue this into Python and get back to what you really love, like performing dictionary comprehensions on multiple keys. You glance over the JPype quick start guide. It has a few useful patterns... set the class path, start the JVM, remove all the type declarations, and you are done. .. code-block:: python # Boiler plate stuff to start the module import jpype import jpype.imports from jpype.types import * # Launch the JVM jpype.startJVM(classpath=['jars/database.jar']) # import the Java modules from com.paying.customer import DataBase # Copy in the patterns from the guide to replace the example code db = Database("our_records") with db.connect() as DatabaseConnection: c.runQuery() while c.hasRecords(): record = db.nextRecord() ... Launch it in the interactive window. You can get back to programming in Python once you get a good night sleep. Case 2: Visualization of Java structures ---------------------------------------- Suppose you are a hard core Java programmer. Weakly typed languages are for wimps, if it isn't garbage collected it is garbage. Unfortunately your latest project has suffered a nasty data structure problem in one of the threads. You managed to capture the data structure in a serialized form but if you could just make graph and call a few functions this would be so much easier. But the interactive Java shell that you are using doesn't really have much in the way of visualization and your don't have time to write a whole graphing applet just to display this dataset. So poking around on the internet you find that Python has exactly the visualization that you need for the problem, but it only runs in CPython. So in order to visualize the structure, you need to get it into Python, extract the data structures and, send it to the plotting routine. You install conda, follow the install instructions to connect to conda-forge, pull JPype1, and launch the first Python interactive environment that appear to produce a plot. You get the shell open and paste in the boilerplate start commands, and load in your serialized object. .. code-block:: python import jpype import jpype.imports jpype.startJVM(classpath = ['jars/*', 'test/classes']) from java.nio.file import Files, Paths from java.io import ObjectInputStream with Files.newInputStream(Paths.get("myobject.ser") as stream: ois = new ObjectInputStream(stream) obj = ois.readObject() print(obj) # prints org.bigstuff.MyObject@7382f612 It appears that the structure is loaded. The problematic structure requires you call the getData method with the correct index. .. code-block:: python d = obj.getData(1) > TypeError: No matching overloads found for org.bigstuff.MyObject.getData(int), > options are: public double[] org.bigstuff.MyObject.getData(double) public double[] org.bigstuff.MyObject.getData(int) Looks like you are going to have to pick the right overload as it can't figure out which overload to use. Darn weakly typed language, how to get the right type in so that you can plot the right data. It says that you can use the casting operators. .. code-block:: python from jpype.types import * d = obj.getData(JInt(1)) print(type(d)) # prints double[] Great. Now you just need to figure out how to convert from a Java array into our something our visualization code can deal with. As nothing indicates that you need to convert the array, you just copy out of the visualization tool example and watch what happens. .. code-block:: python import matplot.pyplot as plt plt.plot(d) plt.show() A graph appears on the screen. Meaning that NumPy has not issue dealing with Java arrays. It looks like ever 4th element in the array is zero. It must be the PR the new guy put in. And off you go back to the wonderful world of Java back to the safety of curly braces and semicolons. Case 3: Interactive Java ------------------------ Suppose you are a laboratory intern running experiments at Hawkins National Laboratory. (For the purpose of this exercise we will ignore the fact that Hawkins was shut down in 1984 and Java was created in 1995). You have the test subject strapped in and you just need to start the experiment. So you pull up Jupyter notebook your boss gave you and run through the cells. You need to added some heart wave monitor to the list of graphed results. The relevant section of the API for the Experiment appears to be .. code-block:: java package gov.hnl.experiment; public interface Monitor { public void onMeasurement(Measurement measurement); } public interface Measurement { public double getTime(); public double getHeartRate(); public double getBrainActivity(); public double getDrugFlowRate(); public boolean isNoseBleeding(); } public class Experiment { public void addCondition(Instant t, Condition c); public void addMoniter(Monitor m); public void run(); } The notebook already has all the test conditions for the experiment set up and the JVM is started, so you just need to implement the monitor. Based on the previous examples, you start by defining a monitor class .. code-block:: python from jpype import JImplements, JOverride from gov.hnl.experiment import Monitor @JImplements(Monitor) class HeartMonitor: def __init__(self): self.readings = [] @JOverride def onMeasurement(self, measurement): self.readings.append([measurement.getTime(), measurement.getHeartRate()]) def getResults(self): return np.array(self.readings) There is a bit to unpack here. You have implemented a Java class from within Python. The Java implementation is simply an ordinary Python class which has be decorated with ``@JImplements`` and ``@JOverride``. When you forgot to place the ``@JOverride``, it gave you the response:: NotImplementedError: Interface 'gov.hnl.experiment.Monitor' requires method 'onMeasurement' to be implemented. But once you added the ``@JOverride``, it worked properly. The subject appears to be getting impatient so you hurry up and set up a short run to make sure it is working. .. code-block:: python hm = HeartMonitor() experiment.addMonitor(hm) experiment.run() readings = hm.getResults() plt.plot(readings[:,0], readings[:,1) plt.show() To your surprise, it says unable to find method addMonitor with an error message:: AttributeError: 'gov.hnl.experiment.Experiment' object has no attribute 'addMonitor' You open the cell and type ``experiment.add``. The line completes with ``experiment.addMoniter``. Whoops, looks like there is typo in the interface. You make a quick correction and see a nice plot of the last 30 seconds pop up in a window. Job well done, so you set the runtime back to one hour. Looks like you still have time to make the intern woodlands hike and forest picnic. Though you wonder if maybe next year you should sign up for another laboratory. Maybe next year, you will try to sign up for those orbital lasers the President was talking about in the March. That sounds like real fun. (This advanced demonstration utilized the concept of Proxies_ and `Code completion`_) The JPype Philosophy ==================== JPype is designed to allow the user to exercise Java as fluidly as possible from within Python. We can break this down into a few specific design goals. - Make Java appear Pythonic. Make it so a Python programmer feels comfortable making use of Java concepts. This means making use of Python concepts to create very Python looking code and at times bending Python concepts to conform to Java's expectations. - Make Python appear like Java. Present concepts from Java with a syntax that resembles Java so that Java users can work with Python without a huge learning curve. - Present everything that Java has to offer to Python. Every library, package, and Java feature if possible should be accessible. The goal of bridge is to open up places and not to restrict flow. - Keep the design as simple as possible. Mixing languages is already complex enough so don't required the user to learn a huge arsenal of unique methods. Instead keep it simple with well defined rules and reuse these concepts. For example, all array types originate from JArray, and thus using one can also use isinstance to check if a class is an array type. Rather than introducing factory that does a similar job to an existing one, instead use a keyword argument on the current factory. - Favor clarity over performance. This doesn't mean not trying to optimize paths, but just as premature optimization is the bane of programmers, requiring writing to maximize speed is a poor long term choice, especially in a language such as Python were weak typing can promote bit rot. - If a new method has to be introduced, make look familiar. Java programmers look to a method named "of" to convert to a type on factories such as a Stream, thus ``JArray.of`` converts a Python NumPy array to Java. Python programmers expect that memory backed objects can be converted into bytes for rapid transfer using a memory view, thus ``memoryview(array)`` will perform that task. - Provide an obvious way for both Python and Java programmers to perform tasks. On this front JPype and Python disagree. In Python's philosophy there should be one -- and preferably only one -- obvious way to do things. But we are bridging two worlds and thus obviousness is in the eye of the beholder. The end result is that JPype has a small footprint while providing access to Java (and other JVM based languages) with a minimum of effort. Languages other than Java ========================= JPype is primarily focused on providing the best possible wrapper for Java in Python. However, the Java Virtual Machine (JVM) is used for many popular languages such a Kotlin and Scala. As such JPype can be used for any language which used the JVM. That said each language has its own special properties that tend to be represented in different ways. If you would like JPype fully to operate on your particular language the following is required. - Set up a test bench for your language under the test directory. Use ivy to pull in the required jar files required to run it and exercise each of the required language features that need to be exercised. - Write a language specific quick start guide for your language defining how things should appear in both your language of choice and within Python highlighting those things that are different from how Java. - Set up a test harness that exercises your language for each language feature and place a setup script like ``test_java`` that builds the harness. Alternatives ============ JPype is not the only Python module of its kind that acts as a bridge to Java. Depending on your programming requirements, one of the alternatives may be a better fit. Specifically JPype is designed for clarity and high levels of integration between the Python and Java virtual machine. As such it makes use of JNI and thus inherits all of the benefits and limitations that JNI imposes. With JPype, both virtual machines are running in the same process and are sharing the same memory space and threads. JPype can thus intermingle Python and Java threads and exchange memory quickly. But by extension you can't start and stop the JVM machine but instead must keep both machines throughout the lifespan of the program. High integration means tightly coupled and thus it embodies the musketeers motto. If Python crashes, so does Java as they only have one process to live in. A few alternatives with different philosophies and limitations are given in the following section. Please take my review comments with the appropriate grain of salt. When I was tasked with finding a replacement for Matlab Java integration for our project test bench, I evaluated a number of alternatives Python bridge codes. I selected JPype primarily because it presented the most integrated API and documentation which would be suitable for getting physicists up to speed quickly. Thus your criteria may yield a different selection. JPype's underlying technology was underwhelming so I have had the pleasure of many hours reworking stuff under the hood. For more details on what you can't do with JPype, please see Limitations_. `Jython `_ ------------------------------- Jython is a reimplementation of Python in Java. As a result it has much lower costs to share data structures between Java and Python and potentially much higher level of integration. Noted downsides of Jython are that it has lagged well behind the state of the art in Python; it has a limited selection of modules that can be used; and the Python object thrashing is not particularly well fit in Java virtual machine leading to some known performance issues. `Py4J `_ --------------------------- Py4J uses a remote tunnel to operate the JVM. This has the advantage that the remote JVM does not share the same memory space and multiple JVMs can be controlled. It provides a fairly general API, but the overall integration to Python is as one would expect when operating a remote channel operating more like an RPC front-end. It seems well documented and capable. Although I haven't done benchmarking, a remote access JVM will have a transfer penalty when moving data. `Jep `_ ------------------------------------- Jep stands for Java embedded Python. It is a mirror image of JPype. Rather that focusing on accessing Java from within Python, this project is geared towards allowing Java to access Python as sub-interpreter. The syntax for accessing Java resources from within the embedded Python is quite similar with support for imports. Notable downsides are that although Python supports multiple interpreters many Python modules do not, thus some of the advantages of the use of Python many be hard to realize. In addition, the documentation is a bit underwhelming thus it is difficult to see how capable it is from the limited examples. `PyJnius `_ -------------------------------------------- PyJnius is another Python to Java only bridge. Syntax is somewhat similar to JPype in that classes can be loaded in and then have mostly Java native syntax. Like JPype, it provides an ability to customize Java classes so that they appear more like native classes. PyJnius seems to be focused on Android. It is written using Cython .pxi files for speed. It does not include a method to represent primitive arrays, thus Python list must be converted whenever an array needs to be passed as an argument or a return. This seems pretty prohibitive for scientific code. PyJnius appears is still in active development. `Javabridge `_ ------------------------------------------------------------------ Javabridge is direct low level JNI control from Python. The integration level is quite low on this, but it does serve the purpose of providing the JNI API to Python rather than attempting to wrap Java in a Python skin. The downside being of course you would really have to know a lot of JNI to make effective use of it. `jpy `_ ------------------------------------- This is the most similar package to JPype in terms of project goals. They have achieved more capabilities in terms of a Java from Python than JPype which does not support any reverse capabilities. It is currently unclear if this project is still active as the most recent release is dated 2014. The integration level with Python is fairly low currently though what they do provide is a similar API to JPype. `JCC `_ ------------------------------------------------ JCC is a C++ code generator that produces a C++ object interface wrapping a Java library via Java's Native Interface (JNI). JCC also generates C++ wrappers that conform to Python's C type system making the instances of Java classes directly available to a Python interpreter. This may be handy if your goal is not to make use of all of Java but rather have a specific library exposed to Python. `VOC _` ---------------------------------------------------------- A transpiler that converts Python bytecode into Java bytecode part of the BeeWare project. This may be useful if getting a smallish piece of Python code hooked into Java. It currently list itself as early development. This is more in the reverse direction as its goals are making Python code available in Java rather providing interaction between the two. `p2j `_ ---------------------------------------------- This lists itself as "A (restricted) python to java source translator". Appears to try to convert Python code into Java. Has not been actively maintained since 2013. Like VOC this is primilarly for code translation rather that bridging. About this guide ================ The JPype User Guide is targeted toward programmers who are strong in either Python who wish to make use of Java or those who are strong with Java and are looking to use Python as a Java development tool. As such we will compare and contrast the differences between the languages and provide examples suitable to help illustrate how to translate from one language to the other on the assumption that being strong in one language will allow you to easily grasp the corresponding relations in the other. If you don't have a strong background in either language an appropriate language tutorial may be necessary. JPype will hide virtually all of the JNI layer such that there is no direct access to JNI concepts. As such attempting to use JNI knowledge will likely lead to incorrect assumptions such as incorrectly attempting to use JNI naming and method signatures in the JPype API. Where JNI limitations do appear we will discuss the consequences imposed in programming. No knowledge of JNI is required to use this guide or JPype. JPype only works with Python 3, thus all examples will be using Python version 3 syntax and assume the use of the Python 3 new style object model. The naming conventions of JPype follow the Java rules rather than those of Python. This is a deliberate choice as it would be dangerous to try to mangle Java method and field names into Python conventions and risk a name collision. Thus if method must have Java conventions then the rest of the module should follow the same pattern for consistency. Getting JPype started --------------------- This document holds numerous JPype examples. For the purposes of clarity the module is assumed to have been started with the following command .. code-block:: python # Import the module import jpype # Allow Java modules to be imported import jpype.imports # Import all standard Java types into the global scope from jpype.types import * # Import each of the decorators into the global scope from jpype import JImplements, JOverride, JImplementationFor # Start JVM with Java types on return jpype.startJVM(convertStrings=False) # Import default Java packages import java.lang import java.util This is not the only style used by JPype users. Some people feel it is best to limit the number for symbols in the global scope and instead start with a minimalistic approach. .. code-block:: python import jpype as jp # Import the module jp.startJVM(convertStrings=False) # Start the module Either style is usable and we do not wish to force any particular style on the user. But as the extra ``jp.`` tends to just clutter up the space and implies that JPype should always be used as a namespace due to namespace conflicts, we have favored the global import style. JPype only exposes 40 symbols total including a few deprecated functions and classes. The 13 most commonly used Java types are wrapped in a special module ``jpype.types`` which can be used to import all for the needed factories and types with a single command without worrying about importing potentially problematic symbols. We will detail the starting process more later in the guide. See `Starting the JVM`_. JPype Concepts *************** At its heart, JPype is about providing a bridge to use Java within Python. Depending on your prospective that can either be a means of accessing Java libraries from within Python or a way to use Java using Python syntax for interactivity and visualization. This mean not only exposing a limited API but instead trying to provide the entirety of the Java language with Python. To do this, JPype maps each of the Java concepts to the nearest concept in Python wherever they are similar enough to operate without confusion. We have tried to keep this as Pythonic as possible, though it is never without some rough edges. Python and Java share many of the same concepts. Types, class, objects, function, methods, and members. But in other places they are rather different. Python lacks casting, type declarations, overloading, and many other features of a strongly typed language, thus we must expose those concepts into the Python syntax as best we can. Java for instance has class annotation and Python have class decorators. Both serve the purpose of augmenting a class with further information, but are very different in execution. We have broken the mapping down in nine distinct concepts. Some elements serve multiple functions. Type Factories These are meta classes that allow one to declare a particular Java type in Python. The result of type factories are wrapper classes. (JClass_ and JArray_) Factories also exist to implement Java classes from within Python (JProxy_) Meta Classes These are classes to describe different properties of Java classes such as to check if a class is an Interface. (JInterface_) Base Classes These are JPype names for Java classes in Python that exist without importing any specific Java class. Concepts such as Object, String, and Exception are defined and can be used in instance checks. For example, to catch all Java exceptions regardless of type, we would catch ``JException``. These are mainly for convenience though they do have some extra functionality. Most of these functions are being phased out in favor of Java syntax. For example, catching ``java.lang.Throwable`` will catch everything that ``JException`` will catch. (Jarray_, JObject_, JString_, and JException_) Wrapper Classes These correspond to each Java class. Thus can be used to access static variables, static methods, cast, and construct object. They are used wherever a Java type would be used in the Java syntax such as creating an array or accessing the class instance. These class wrappers are customized in Python to allow a direct mapping from Java concepts to Python one. These are all created dynamically corresponding to each Java class. For most of this document we will refer to these simply as a "class". (`java.lang.Object`_, `java.lang.String`_, etc) Many wrappers are customized to match Python abstract base classes ABC (`java.util.List`_, `java.util.Map`_) Object Instances These are Java objects. They operate just like Python objects with Java public fields mapped to Python attributes and Java methods to Python methods. For this document we will refer to an object instance simply as an "object". The object instance is split into two halves. The Python portion is referred to as the "handle" that points the Java "instance". The lifetime of the "instance" is tied to the handle thus Java objects do not disappear until the Python handle is disposed of. Objects can be cast_ to match the required type and hold methods_ and fields. `Primitive types`_ Each of the 8 Java primitive types are defined. These are used to cast to a Java type or to construct arrays. (`JBoolean`_, `JChar`_, `JByte`_, `JShort`_, `JInt`_, `JLong`_, `JFloat`_, and `JDouble`_) Decorators Java has a number of keywords such as extending a class or implementing an interface. Those pieces of meta data can't directly be expressed with the Python syntax, but instead have been been expressed as annotations that can be placed on classes or functions to augment them with Java specific information. (`@JImplements`_, `@JOverride`_, `@JImplementationFor`_) Mapping Java syntax to Python Many Java concepts like try with resources can be mapped into Python directly (as the ``with`` statement), or Java try, throw, catch mapping to Python try, raise, except. Others such as synchronize do not have an exact Python match. Those have instead been mapped to special functions that interact with Python syntax.. (synchronized_, `with`, `try`, import_) JVM control functions The JVM requires specific actions corresponding to JNI functions in order to start, shutdown, and define threading behavior. These top level control functions are held in the ``jpype`` module. (startJVM_, shutdownJVM_) We will detail each of these concepts in greater detail in the later sections. Name mangling ============= When providing Java package, classes, methods, and fields to Python, there are occasionally naming conflicts. For example, if one has a method called ``with`` then it would conflict with the Python keyword ``with``. Wherever this occurs, JPype renames the offending symbol with a trailing under bar. Java symbols with a leading or trailing under bars are consider to be privates and may not appear in the JPype wrapper entirely with the exception of package names. The following Python words will trigger name mangling of a Java name: =========== =========== ============= =========== ========== ``False`` ``None`` ``True`` ``and`` ``as`` ``async`` ``await`` ``def`` ``del`` ``elif`` ``except`` ``exec`` ``from`` ``global`` ``in`` ``is`` ``lambda`` ``nonlocal`` ``not`` ``or`` ``pass`` ``print`` ``raise`` ``with`` ``yield`` =========== =========== ============= =========== ========== JPype Types *********** Both Java and Python have a concept of a type. Every variable refers to an object which has a defined type. A type defines the data that the variable is currently holding and how that variable can be used. In this chapter we will learn how Java and Python types relate to one another, how to create import types from Java, and how to use types to create Java objects. Stay strong in a weak language ============================== Before we get into the details of the types that JPype provides, we first need to contrast some of the fundamental language differences between Java and Python. Python is inherently a weakly typed language. Any variable can take any type and the type of a particular variable can change over the lifetime of a program. Types themselves can be mutable as you can patch an existing type to add new behaviors. Python methods can in principle take any type of object as an argument, however if the interface is limited it will produce a TypeError to indicate a particular argument requires a specific type. Python objects and classes are open. Each class and object is basically a dictionary storing a set of key value pairs. Types implemented in native C are often more closed and thus can't have their method dictionaries or data members altered arbitrarily. But subject to a few restrictions based implementation, it is pretty much the wild west. In contrast, Java is a strongly typed language. Each variable can only take a value of the specified class or a class that derives from the specified class. Each Java method takes only a specific number and type of arguments. The type and number are all checked at compile type to ensure there is little possibility of error. As each method requires a specific number and type of arguments, a method can be overloaded by having two different implementations which take a different list of types sharing the same method name. A primitive variable can never hold an object and it can only be converted to or from other primitive types unless it is specifically cast to that type. Java objects and classes are completely closed. The methods and fields for a particular class and object are defined entirely at compile time. Though it is possible create classes with a dictionary allowing expansion, this is not the Java norm and no standard mechanism exists. Thus we need to introduce a few Java terms to the Python vocabulary. These are "conversion" and "cast". Java conversions ---------------- A conversion is a permitted change from an object of one type to another. Conversions have three different degrees. These are: exact, implicit, and explicit. Exact conversions are those in which the type of an object is identical. In Java each class has only one definition thus there is no need for an exact conversion. But when dealing with Python we have objects that are effectively identical for which exact conversion rules apply. For example, a Java string and a Python string both bind equally well to a method which requires a string, thus this is an exact conversion for the purposes of bind types. The next level of conversion is implicit. An implicit conversion is one that Java would perform automatically. For example converting a derived class to is base class when setting a field would be an implicit conversion. Java defines a number of other conversions such as converting a primitive to a boxed type or from a boxed type back to a primitive as implicit conversions.. Of course not every cast is safe to perform. For example, converting an object whose type is currently viewed as a base type to a derived type is not performed automatically nor is converting from one boxed type to another. For those operations the conversion must be explicitly requested, hence these are explicit conversions. To request an explicit conversion an object must be "cast" using a cast operator. In Java, a cast is requested by placing the type name in parentheses in front of the object to be cast. Unfortunately, the same syntax is not allowed in Python. Not every conversion is possible between Java types. Types that cannot be converted are considerer to be conversion type "none". Details on the standard conversions provided by JPype are given in the section `Type Matching`_. .. _cast: Java casting ------------ To access a casting operation we use the casting ``JObject`` wrapper. JObject accepts two arguments. The first argument is the object to convert and the second is the type to cast to. The second argument should always be a Java type specified using a class wrapper, a Java class instance, or a string. Casting will also add a hidden class argument to the resulting object such that it is treated as the cast type for the duration of that variable lifespan. Therefore, a variable create by casting is stuck as that type and cannot revert back to its original for the purposes of method resolution. The object construction and casting are sometimes a bit blurry. For example, when one casts a sequence to a Java list, we will end up constructing a new Java list that contains the elements of the original Python sequence. In general JPype constructors only provide access the Java constructor methods that are defined in the Java documentation. Casting on the other hand is entirely the domain of whatever JPype has defined including user defined casts. .. _JObject: Casting is performed through the Python class ``JObject``. JObject is called with two arguments which are the object to be cast and the type to cast too. The cast first consults the conversion table to decide if the cast it permitted and produces a ``TypeError`` if the conversion is not possible. ``JObject`` also serves as a abstract base class for testing if an object instance belongs to Java. All objects that belong to Java will return true when tested with ``isinstance``. Like Python's sequence, JObject is an abstract base class. No classes actual derive from ``JObject``. .. _null: Of particular interest is the concept of Java ``null``. In Java, null is a typeless entity which can be placed wherever an object is taken to indicate that the object is not available. The equivalent concept in Python is ``None``. Thus all methods that accept any object type that permit a null will accept None as an augment with implicit conversion. However, sometime it is necessary to pass an explicit type to the method resolution. To achieve this in JPype use ``JObject(None, type)`` which will create a null pointer with the desired type. To test if something is null we have to compare the handle to None. This unfortunately trips up some code quality checkers. The idiom in Python is ``obj is None``, but as this only matches things that Python considers identical, we must instead use ``obj==None``. Type enforcement appears in three different places within JPype. These are whenever a Java method is called, whenever a Java field is set, and whenever Python returns a value back to Java. .. _methods: Method resolution ================= Because Java supports method overloading and Python does not, JPype wraps Java methods as a "method dispatch". The dispatch is a collection of all of the methods from class and all of its parents which share the same name. The job of the dispatch is chose the method to call. Enforcement of the strong typing of Java must be performed at runtime within Python. Each time a method is invoked, JPype must match against the list of all possible methods that the class implements and choose the best possible overload. For this reason the methods that appear in a JPype class will not be the actual Java methods, but rather a "dispatch" whose job is deciding which method should be called based on the type of the provided arguments. If no method is found that matches the provided arguments, the method dispatch will produce a ``TypeError``. This is the exact same outcome that Python uses when enforcing type safety within a function. If a type doesn't match a ``TypeError`` will be produced. Dispatch example ---------------- When JPype is unable to decide which overload of a method to call, the user must resolve the ambiguity. This is where casting comes in. Take for example the ``java.io.PrintStream`` class. This class has a variant of the print and println methods! So for the following code: .. code-block:: python java.lang.System.out.println(1) JPype will automatically choose the ``println(long)`` method, because the Python int matches exactly with the Java long, while all the other numerical types are only "implicit" matches. However, if that is not the version you wanted to call you must cast it. In this case we will use a primitive type to construct the correct type. Changing the line thus: .. code-block:: python java.lang.System.out.println(JByte(1)) # <--- wrap the 1 in a JByte This tells JPype to choose the byte version. When dealing with Java types, JPype follows the standard Java matching rules. Types can implicitly grow to larger types but will not shrink without an explicit cast. Primitive Types =============== Unlike Python, Java makes a distinction between objects and primitive data types. Primitives represent the minimum data that can be manipulated by a computer. These stand in contrast to objects which have the ability to contain any combination of data types and object within themselves, and can be inherited from. Java primitives come in three flavors. The logical primitive ``boolean`` can only take the logical value true and false. The textual primitive ``char`` represents one character in a string. Numerical primitives are intended for fixed point or floating point calculations. Numerical primitives come in many sizes depending on how much storage is required. In Java, integer numerical primitives are always signed and thus can only reach half their range in terms of bits up or down relative to their storage size. JPype has mapped each of the primitive types into Python classes. To avoid conflicts with Python, JPype has named each primitive with a capital letter ``J`` followed by the primitive name starting with an upper case letter. .. _JBoolean: JBoolean A boolean is the logical primitive as it can only take values ``True`` and ``False``. It should properly be an extension of the Python concept ``bool`` but that type is not extendable. Thus instead it must inherit from ``int``. This type is rarely seen in JPype as the values ``True`` and ``False`` are considered an exact match to ``JBoolean`` argument. Methods which return a ``JBoolean`` will always return a Python ``bool`` rather than a Java primitive type. .. _JChar: JChar A character is the textual primitive that corresponds to exactly one character in a string. Or at least that was the concept at the time. Java characters can only represent 16 bits. But there are currently 143,924 defined characters in Unicode. Thus, there are certain characters that can only be represented as two Unicode characters. The textual primitives are not intended to perform numerical functions, but are instead encoded. As per the old joke, what does `1` plus `1` equal? Which of course the correct answer is `b`. As such characters should not be treated as just another unsigned short. Python has no concept of a textual only type. Thus when returning a character type, we instead return a string length 1. ``JChar`` supports the Java numerical operations, but just as in Java it will automatically promote to a Python ``int`` when used in a numerical operation. There are of course lots of useful mathematical operations that can be performed on textual primitives, but doing so risks breaking the encoding and can result in uninterpretable data. .. _JByte: .. _JShort: .. _JInt: .. _JLong: JByte, Short, Int, Long These types represent fixed point quantities with ranges of 8, 16, 32, and 64 bits. Each of these type inherit from a Python ``int`` type. A method or field returning an integer primitive will return a type derived from ``int``. Methods accepting an integer primitive will take either an Java integer primitive or a Python ``int`` or anything that quacks like a ``int`` so long as it can be converted into that primitive range without truncation. .. _JFloat: .. _JDouble: JFloat, JDouble These two types hold floating point and correspond to either single point (32 bit) or double point (64 bit) precision. Python does not have a concept of precision and thus both of these derive from the Python type ``float``. As per Java rules numbers greater than the range correspond to the values of positive and negative infinity. Conversions from Python types are ranged check and will produce a ``OverflowError`` if the value doesn't fit into the request types. If an overflow error is not desired, first cast the value into the request size prior to calling. Methods that return a Java floating point primitive will always return a value derived from ``float``. The classes for Java primitives are closed and should not be extended. As with all Java values any information attached to the Python representation is lost when passing that value to Java. Objects & Classes ================= In contrast to primitive data type, objects can hold any combination of primitives or objects. Thus they represent structured data. Objects can also hold methods which operate on that data. Objects can inherit from one another. However unlike Python, Java objects must have a fixed structure which defines its type. These are referred to the object's class. Here is a point of confusion. Java has two different class concepts: the class definition and the class instance. When you import a class or refer to a method using the class name you are accessing the class definition. When you call ``getClass`` on an object it returns a class instance. The class instance is a object whose structure can be used to access the data and methods that define the class through reflection. The class instance cannot directly access the fields or method within a class but instead provides its own interface for querying the class. For the purposes of this document a "class" will refer to the class definition which corresponds to the Python concept of a class. Wherever the Java reflection class is being referred to we will use the term "class instance". The term "type" is synonymous with a "class" in Java, though often the term "type" is only used when inclusively discussing the type of primitives and objects, while the term "class" generally refers to just the types associated with objects. All objects in Java inherit from the same base class ``java.lang.Object``, but Java does not support multiple inheritance. Thus each class can only inherit from a single parent. Multiple inheritance, mix-ins, and diamond pattern are not possible in Java. Instead Java uses the concept of an interface. Any Java class can inherit as many interfaces as it wants, but these interfaces may not contain any data elements. As they do not contain data elements there can be no ambiguity as to what data a particular lookup. .. _JInterface: The meta class ``JInterface`` is used to check if a class type is an interface using ``isinstance``. Classes that are pure interfaces cannot be instantiated, thus, there is not such thing as an abstract instance. Therefore, every Java object should have Objects cannot actual be pure interfaces. To represent this in Python every interface inherits ``java.lang.Object`` methods even through it does not have ``java.lang.Object`` as a parent. This ensures that anonymous classes and lambdas have full object behavior. Classes ------- In JPype, Java classes are instances of the Python ``type`` and function like any ordinary Python class. However unlike Python types, Java classes are closed and cannot be extended. To enforce extension restrictions, all Java classes are created from a special private meta class called ``_jpype._JClass``. This gatekeeper ensures that the attributes of classes cannot be changed accidentally nor extended. The type tree of Java is fixed and closed. All Java classes have the following functionality. Class constructor The class constructor is accessed by using the Python call syntax ``()``. This special method invokes a dispatch whenever the class is called as a function. If an matching constructor is found a new Java instance is created and a Python handle to that instance is returned. In the case of primitive types, the constructor creates a Java value with the exact type requested. Get attribute The Python ``.`` operator gets an attribute from a class with a specified name. If no method or field exists a ``AttributeError`` will be raised. For public static methods, the getattr will produce a Python descriptor which can be called to invoke the static method. For public static fields, a Python descriptor will be produced that allows the field to be get or set depending on whether the field is final or not. Public instance methods and instance fields will produce a function that can be applied to a Java object to execute that method or access the field. Function accessors are non-virtual and thus they can provide access to behaviors that have been hidden by a derived class. Set attribute In general, JPype only allows the setting of public non-final fields. If you attempt to set any attribute on an object that does not correspond to a settable field it will produce an ``AttributeError``. There is one exception to this rule. Sometime it is necessary to attach addition private meta data to classes and objects. Attributes that begin with an underbar are consider to be Python private attributes. Private attributes handled by the default Python attribute handler allowing these attributes to be attached to to attach data to the Python handle. This data is invisible to Java and it is retained only on the Python instance. If an object with Python meta data is passed to Java and Java returns the object, the new Python handle will not contain any of the attached data as this data was lost when the object was passed to Java. ``class_`` Attribute For Java classes there is a special attribute called ``class``. This is a keyword in Python so `name mangling`_ applies. This is a class instance of type ``java.lang.Class``. It can be used to access fields and methods. Inner classes For methods and fields, public inner classes appear as attributes of the class. These are regular types that can be used to construct objects, create array, or cast. String The Java method ``toString`` is mapped into the Python function ``str(obj)``. Equality The Java method ``equals()`` has been mapped to Python ``==`` with special augmentations for null pointers. Java ``==`` is not exposed directly as it would lead to numerous errors. In principle, Java ``==`` should map to the Python concept of ``is`` but it is not currently possible to overload Python in such a way to achieve the desired effect. Hash The Java method ``hashCode`` is mapped to Python ``hash(obj)`` function. There are special augmentations for strings and nulls. Strings will return the same hash code as returned by Python so that Java strings and Python strings produce the same dictionary lookups. Null pointers produce the same hash value as None. Java defines ``hashCode`` on many objects including mutable ones. Often the ``hashCode`` for a mutable object changes when the object is changed. Only use immutable Java object (String, Instant, Boxed types) as dictionary keys or risk undefined behavior. Java objects are instances of Java classes and have all of the methods defined in the Java class including static members. However, the get attribute method converts public instance members and fields into descriptors which act on the object. Now that we have defined the basics of Java objects and classes, we will define a few special classes that operate a bit differently. Array Classes ------------- In Java all arrays are also objects, but they cannot define any methods beyond a limited set of Java array operations. These operations have been mapped into Python to their closest Python equivalent. Arrays also have a special type factory to produce them. In principle one can create an array class using ``JClass`` but the signature required would need to use the proper name as required for the Java method ``java.lang.Class.forName``. Instead we call the factory to create a new type to use. .. _JArray: The signature for JArray is ``JArray(type, [dims=1])``. The type argument accepts any Java type including primitives and constructs a new array class. This class can be used to create new instances, cast, or as the input to the array factory. The resulting object has a constructor method which take either a number, which is the desired size of the array, or a sequence which hold the elements of the array. If the members of the initializer sequence are not Java members then each will be converted. If any element cannot be converted a ``TypeError`` will be raised. JArray is an abstract base class for all Java classes that are produced. Thus, one can test if something is an array class using ``issubclass`` and if Java object is an array using ``isinstance``. Java arrays provide a few additional Python methods: Get Item Arrays are of course a collection of elements. As such array elements can be accessed using the Python ``[]`` operator. For multidimensional arrays JPype uses Java style access with a series of index operations such as ``jarray[4][2]`` rather than NumPy like multidimensional access. Get Slice Arrays can be accessed using a slice like a Python list. The slice operator is ``[start:stop:step]``. It should be noted that array slice are in fact views to the original array so any alteration to the slice will affect the original array. Array slices are cloned when passed back to Java. To force a clone immediately, use the ``clone`` method. Please note that applying the slice operator to a slice produces a new slice. Thus there can sometimes be an ambiguity between multidimensional access and repeated slicing. Set Item Array items can be set using the Python ``[]=`` operator. Set Slice Multiple array items can be set using a slice assigned with a sequence. The sequence must have the same length as the slice. If this condition is not met, an exception will be raised. If the items to be transferred are a buffer, then a faster buffer transfer assignment will be used. When buffer transfers are used individual elements are not checked for range, but instead cast just like NumPy. Thus, if we have the elements we wish to assign to the array contained within a NumPy array named ``na`` we can transfer all of them using ``jarray[:] = na``. Buffer transfer Buffer transfers from a Java array also work for primitive types. Thus we can simply call the Python ``memoryview(jarray)`` function to create a buffer that can be used to transfer any portion of a Java array out. Memory views of Java arrays are not writable. For each Java arrays can be used as the input to a Python for statement. To iterate each element use ``for elem in jarray:``. They can also be used in list comprehensions. Clone Java arrays can be duplicated using the method clone. To create a copy call ``jarray.clone()``. This operates both on arrays and slice views. Length Arrays in Java have a defined an immutable length. As such the Python ``len(array)`` function will produce the array length. However, as that does not match Java expectations, JPype also adds an attribute for length so that Java idiom ``jarray.length`` also works as expected. In addition, the Java class ``JChar[]`` has some addition customizations to help work better with string types. Java arrays are currently missing some of the requirements to act as a ``collections.abc.Sequence``. When working with Java arrays it is also useful to use the Java array utilities class ``java.util.Arrays`` as it has many methods that provide additional functionality. Java arrays do not support any additional mathematical operations at this time. Buffer classes -------------- In addition to array types, JPype also supports Java ``nio`` buffer types. Buffers in Java come in two flavors. Array backed buffers have no special access. Direct buffers are can converted to Python buffers with both read and write capabilities. Each primitive type in Java has its own buffer type named based on the primitive type. ``java.nio.ByteBuffer`` has the greatest control allowing any type to be read and written to it. Buffers in Java function are like memory mapped files and have a concept of a read and write pointer which is used to traverse the array. They also have direct index access to their specified primitive type. Java buffer provide an additional Python method: Buffer transfer Buffer transfers from a Java buffer works for a direct buffer. Array backed buffers will raise a ``BufferError``. Use the Python ``memoryview(jarray)`` function to create a buffer that can be used to transfer any portion of a Java buffer out. Memory views of Java buffers are readable and writable. Buffers do not currently support element-wise access. Boxed Classes ------------- Often one wants to be able to place a Java primitive into a method of fields that only takes an object. The process of creating an object from a primitive is referred to as creating a "boxed" object. The resulting object is an immutable object which stores just that one primitive. Java boxed types in JPype are wrapped with classes that inherit from Python ``int`` and ``float`` types as both are immutable in Python. This means that a boxed type regardless of whether produced as a return or created explicitly are treated as Python types. They will obey all the conversion rules corresponding to a Python type as implicit matches. In addition, they produce an exact match with their corresponding Java type. The type conversion for this is somewhat looser than Java. While Java provides automatic unboxing of a Integer to a double primitive, JPype can implicitly convert Integer to a Double boxed. To box a primitive into a specific type such as to place it into a ``java.util.List`` use ``JObject`` on the desired boxed type or call the constructor for the desired boxed type directly. For example: .. code-block:: python lst = java.util.ArrayList() lst.add(JObject(JInt(1))) # Create a Java integer and box it lst.add(java.lang.Integer(1)) # Explicitly create the desired boxed object JPype boxed classes have some additional functionality. As they inherit from a mathematical type in Python they can be used in mathematical operations. But unlike Python numerical types they can take an addition state corresponding to being equal to a null pointer. The Python methods are not aware of this new state and will treat the boxed type as a zero if the value is a null. To test for null, cast the boxed type to a Python type explicitly and the result will be checked. Casting null pointer will raise a ``TypeError``. .. code-block:: python b = JObject(None, java.lang.Integer) a = b+0 # This succeeds and a gets the value of zero a = int(b)+0 # This fails and raises a TypeError Boxed objects have the following additional functionality over a normal object. Convert to index Integer boxed types can be used as Python indices for arrays and other indexing tasks. This method checks that the value of the boxed type is not null. Convert to int Integer and floating point boxed types can be cast into a Python integer using the ``int()`` method. The resulting object is always of type ``int``. Casting a null pointer will raise a ``TypeError``. Convert to float Integer and floating point boxed types can be cast into a Python float using the ``float()`` method. The resulting object is always of type ``float``. Casting a null pointer will raise a ``TypeError``. Comparison Integer and floating point types implement the Python rich comparison API. Comparisons for null pointers only succeed for ``==`` and ``!=`` operations. Non-null boxed types act like ordinary numbers for the purposes of comparison. Number Class ------------ The Java class ``java.lang.Number`` is a special type in Java. All numerical Java primitives and Python number types can convert implicitly into a Java Number. ========================== ======================== Input Result ========================== ======================== None java.lang.Number(null) Python int, float java.lang.Number Java byte, NumPy int8 java.lang.Byte Java short, NumPy int16 java.lang.Short Java int, NumPy int32 java.lang.Integer Java long, NumPy int64 java.lang.Long Java float, NumPy float32 java.lang.Float Java double, NumPy float64 java.lang.Double ========================== ======================== Additional user defined conversion are also applied. The primitive types boolean and char and their corresponding boxed types are not considered to numbers in Java. .. _java.lang.Object: Object Class ------------ Although all classes inherit from Object, the object class itself has special properties that are not inherited. All Java primitives will implicitly convert to their box type when placed in an Object. In addition, a number of Python types implicitly convert to a Java object. To convert to a different object type, explicitly cast the Python object prior to placing in a Java object. Here a table of the conversions: ================ ======================= Input Result ================ ======================= None java.lang.Object(null) Python str java.lang.String Python bool java.lang.Boolean Python int java.lang.Number Python float java.lang.Number ================ ======================= In addition it inherits the conversions from ``java.lang.Number``. Additional user defined conversion are also applied. .. _java.lang.String: String Class ------------ The String class in Java is a special representation often pointing either to a dynamically created string or to a constant pool item defined in the class. All Java strings are immutable just like Python strings and thus these are considered to be equivalent classes. Because Java strings are in fact just pointers to blob of bytes they are actually slightly less than a full object in some JVM implementation. This is a violation of the Object Orients (OO) principle, never take something away by inheritance. Unfortunately, Java is a frequent violator of that rule, so this is just one of those exceptions you have to trip over. Therefore, certain operations such as using a string as a threading control with ``notify`` or ``wait`` may lead to unexpected results. If you are thinking about using a Java string in synchronized statement then remember it is not a real object. Java strings have a number of additional functions beyond a normal object. Length Java strings have a length measured in the number of characters required to represent the string. Extended Unicode characters count for double for the purpose of counting characters. The string length can be determined using the Python ``len(str)`` function. Indexing Java strings can be used as a sequence of characters in Python and thus each character can be accessed as using the Python indexing operator ``[]``. Hash Java strings use a special hash function which matches the Python hash code. This ensures that they will always match the same dictionary keys as the corresponding string in Python. The Python hash can be determined using the Python ``hash(str)`` function. Null pointers are not currently handled. To get the actually Java hash, use ``s.hashCode()`` Contains Java strings implement the concept of ``in`` when using the Java method ``contains``. The Java implementation is sufficiently similar that it will work fairly well on strings. For example, ``"I" in java.lang.String("team")`` would be equal to False. Testing other types using the ``in`` operator will likely raise a ``TypeError`` if Java is unable to convert the other item into something that can be compared with a string. Concatenation Java strings can be appended to create a new string which contains the concatenation of the two strings. This is mapped to the Python operator ``+``. Comparison Java strings are compared using the Java method ``compareTo``. This method does not currently handle null and will raise an exception. For each Java strings are treated as sequences of characters and can be used with a for-loop construct and with list comprehension. To iterate through all of the characters, use the Python construct ``for c in str:``. Unfortunately, Java strings do not yet implement the complete list of requirements to act as Python sequences for the purposes of ``collections.abc.Sequence``. .. _JString: The somewhat outdated JString factory is a Python class that pretends to be a Java string type. It has the marginal advantage that it can be imported before the JVM is actually started. Once the JVM is started, its class representation is pointed to ``java.lang.String`` and can be used to construct a new string object or to test if an object is actually a Java string using ``isinstance``. It does not implement any of the other string methods and just serves as convenience class. The more capable ``java.lang.String`` can be imported in place of JString, but only after the JVM is started. String objects may optionally convert to Python strings when returned from Java methods, though this option is a performance issue and can lead to other difficulties. This setting is selected when the JVM is started. See `String Conversions`_ for details. Java strings will cache the Python conversion so we only pay the conversion cost once per string. Exception Classes ----------------- Both Python and Java treat exception classes differently from other objects. Only these types may be caught as part of a try block. Therefore, the exceptions have a special wrapper. Most of the mechanics of exceptions happen under the surface. The one difference between Python and Java is the behavior when the argument is queried. Java arguments can either be the string value, the exception itself, or the internal construction key depending on how the exception came into existence. Therefore, the arguments to a Java exception should never be used as their values are not guaranteed. Java exception can report their stacktrace to Python in two different ways. If printed through the Python stack trace routine, Java exceptions are split between the Python code that raised and a phantom Java ``cause`` which contains the Java exception in Python order. If the debugging information for the Java source is enabled, Python may even print the Java source code lines where the error occurred. If you prefer Java style stack traces then print the result from the ``stacktrace()`` method. Unhandled exception that terminate the program will print the Python style stack trace information. .. _JException: The base class ``JException`` is a special type located in ``jpype.types`` that can be imported prior to the start of the JVM. This serves as the equivalent of ``java.lang.Throwable`` and contains no additional methods. It is currently being phased out in favor of catching the Java type directly. Using ``jpype.JException`` with a class name as a string was supported in previous JPype versions but is currently deprecated. For further information on dealing with exception, see the `Exception Handling`_ section. To create a Java exception use JClass or any of the other importing methods. Anonymous Classes ----------------- Sometimes Java will produce an anonymous class which does to have any actual class representation. These classes are generated when a method implements a class directly as part of its body and they serve as a closure with access to some of the variables that were used to create it. For the purpose of JPype these classes are treated as their parents. But this is somewhat problematic when the parent is simply an interface and not an actual object type. Lambdas ------- The companion of anonymous classes are lambda classes. These are generated dynamically and their parent is always an interface. Lambdas are always Single Abstract Method (SAM) type interfaces. They can implement additional methods in the form of default methods but those are generally not accessible within JPype. Inner Classes ------------- For the most part, inner classes can be used like normal classes, with the following differences: - Inner classes in Java natively use $ to separate the outer class from the inner class. For example, inner class Foo defined inside class Bar is called Bar.Foo in Java, but its real native name is Bar$Foo. - Inner classes appear as member of the containing class. Thus to access them import the outer class and call them as members. - Non-static inner classes cannot be instantiated from Python code. Instances received from Java code can be used without problem. .. _import: Importing Java classes ====================== As Java classes are remote from Python and can neither be created nor extended within Python, they must be imported. JPype provides three different methods for creating classes. The highest level API is the use of the import system. To import a Java class, one must first import the optional module ``jpype.imports`` which has the effect of binding the Java package system to the Python module lookup. Once this is completed package or class can be imported using the standard Python import system. The import system offers a very rich error reporting system. All failed imports produce an ``ImportError`` with diagnostics as to what went wrong. Errors include unable to find the class, unable to find a required dependency, and incorrect Java version. One important caveat when dealing with importing Java modules. Python always imports local directories as modules before calling the Java importer. So any directory named ``java``, ``com``, or ``org`` will hide corresponding Java package. We recommend against naming directories as ``java`` or top level domain. .. _JPackage: The older method of importing a class is with the ``JPackage`` factory. This factory automatically loads classes as attributes as requested. If a class cannot be found it will produce an ``AttributeError``. The symbols ``java`` and ``javax`` in the ``jpype`` module are both ``JPackage`` instances. Only public classes appear on ``JPackage`` but protected and even private classes can be accessed by name. Though most private classes don't have any methods or fields that can be accessed. .. _JClass: The last mechanism for looking up a class is through the use of the ``JClass`` factory. This is a low level API allowing the loading of any class available using the forName mechanism in Java. The JClass method can take up to three arguments corresponding to arguments of the forName method and can be used with alternative class loaders. The majority of the JPype test bench uses JClass so that the tests are only evaluating the desired functionality and not the import system. But this does not imply that JClass is the preferred mechanic for importing classes. The first argument can be a string or a Java class instance. There are two keyword arguments ``loader`` and ``initialize``. The loader can point to an alternative ClassLoader which is handy when loading custom classes through mechanisms such as over the web. A False ``initialize`` argument loads a class without loading dependencies nor populating static fields. This option is likely not useful for ordinary users. It was provided when calling forName was problematic due to `caller sensitive`_ issues. Type Matching ============= This section provides tables documenting the JPype conversion rules. JPype defines different levels of "match" between Python objects and Java types. These levels are: - **none**, There is no way to convert. - **explicit (E)**, JPype can convert the desired type, but only explicitly via casting. Explicit conversions are only execute automatically in the case of a return from a proxy. - **implicit (I)**, JPype will convert as needed. - **exact (X)**, Like implicit, but when deciding with method overload to use, one where all the parameters match "exact" will take precedence over "implicit" matches. See the previous section on `Java Conversions`_ for details. There are special conversion rules for ``java.lang.Object`` and ``java.lang.Number``. (`Object Class`_ and `Number Class`_) ============== ========== ========= =========== ========= ========== ========== =========== ========= ========== =========== ========= ================== ================= Python\\Java byte short int long float double boolean char String Array Object java.lang.Object java.lang.Class ============== ========== ========= =========== ========= ========== ========== =========== ========= ========== =========== ========= ================== ================= int I [1]_ I [1]_ X I I [3]_ I [3]_ X [8]_ I [11]_ long I [1]_ I [1]_ I [1]_ X I [3]_ I [3]_ I [11]_ float I [1]_ X I [11]_ sequence dictionary string I [2]_ X I unicode I [2]_ X I JByte X I [9]_ JShort X I [9]_ JInt X I [9]_ JLong X I [9]_ JFloat X I [9]_ JDouble X I [9]_ JBoolean X I [9]_ JChar X I [9]_ JString X I JArray I/X [4]_ I JObject I/X [6]_ I/X [7]_ I/X [7]_ JClass I X "Boxed"[10]_ I I I I I I I I ============== ========== ========= =========== ========= ========== ========== =========== ========= ========== =========== ========= ================== ================= .. [1] Conversion will occur if the Python value fits in the Java native type. .. [2] Conversion occurs if the Python string or unicode is of length 1. .. [3] Java defines conversions from integer types to floating point types as implicit conversion. Java's conversion rules are based on the range and can be lossy. See (http://stackoverflow.com/questions/11908429/java-allows-implicit-conversion-of-int-to-float-why) .. [4] Number of dimensions must match and the types must be compatible. .. [6] Only if the specified type is a compatible array class. .. [7] The object class is an exact match, otherwise implicit. .. [8] Only the values `True` and `False` are implicitly converted to booleans. .. [9] Primitives are boxed as per Java rules. .. [10] Java boxed types are mapped to Python primitives, but will produce an implicit conversion even if the Python type is an exact match. This is to allow for resolution between methods that take both a Java primitve and a Java boxed type. .. [11] Boxed to ``java.lang.Number`` Exception Handling ================== Error handling is an important part of any non-trivial program. All Java exceptions occurring within Java code raise a ``jpype.JException`` which derives from Python Exception. These can be caught either using a specific Java exception or generically as a ``jpype.JException`` or ``java.lang.Throwable``. You can then use the ``stacktrace()``, ``str()``, and args to access extended information. Here is an example: .. code-block:: python try : # Code that throws a java.lang.RuntimeException except java.lang.RuntimeException as ex: print("Caught the runtime exception : ", str(ex)) print(ex.stacktrace()) Multiple java exceptions can be caught together or separately: .. code-block:: python try: # ... except (java.lang.ClassCastException, java.lang.NullPointerException) as ex: print("Caught multiple exceptions : ", str(ex)) print(ex.stacktrace()) except java.lang.RuntimeException as ex: print("Caught runtime exception : ", str(ex)) print(ex.stacktrace()) except jpype.JException: print("Caught base exception : ", str(ex)) print(ex.stacktrace()) except Exception as ex: print("Caught python exception :", str(ex)) Exceptions can be raised in proxies to throw an exception back to Java. Exceptions within the JPype core are issued with the most appropriate Python exception type such as ``TypeError``, ``ValueError``, ``AttributeError``, or ``OSError``. Exception aliasing ------------------ Certain exceptions in Java have a direct correspondence with existing Python exceptions. Rather than forcing JPype to translate these exceptions, or forcing the user to handle Java exception types throughout the code, we have "derived" these exceptions from their Python counter parts. Thus, rather than requiring special error handling for Java you can simple catch these exceptions using the standard Python exception types. `java.lang.IndexOutOfBoundsException` This exception is synonymous with the Python exception ``IndexError``. As many slicing or array operations in Java can produce an IndexOutOfBoundsException but the Python contract for slicing of an array should raise an ``IndexError``, this type has been customized to consider IndexError to be a base type. `java.lang.NullPointerException` This exception is derived from the Python exception ``ValueError``. Numerous Java calls produce a ``NullPointerException`` and in all cases this would match a Python ``ValueError``. By deriving these exceptions from Python, the user is free to catch the exception either as a Java exception or as the more general Python exception. Remember that Python exceptions are evaluated in order from most specific to least. Controlling the JVM ******************* In this chapter, we will discuss how to control the JVM from within Python. For the most part, the JVM is invisible to Python. The only user controls needed are to start up and shutdown the JVM. .. _startJVM: Starting the JVM ================ The first task is always to start the JVM. The settings to the JVM are immutable over the lifespan of the JVM. The user settings are: the JVM arguments, the class path used to find jars, and whether to convert Java strings to Python strings. Class paths ----------- JPype supports two styles of classpaths. The first is modeled after Matlab the second argument style uses a list to the ``startJVM`` function. The Matlab style uses the functions ``jpype.addClassPath`` and ``getClassPath``. The first function adds a directory or jar file to the search path. Wild cards are accepted in the search. Once all of the paths are added to internal class path, they can be retrieved using ``getClassPath`` which takes a keyword argument ``env`` which defaults to true. When set to false, JPype will ignore the environment variable ``CLASSPATH`` which is normally included in the default classpath. To use the argument style, pass all of the class paths in a list as the keyword argument ``classpath`` to the ``startJVM``. This classpath method does not include the environment ``CLASSPATH``, but it does provide a quick method to pull in a specific set of classes. Wild cards are accepted as the end of the path to include all jars in a given directory. One should note that the class path can only be set prior starting the JVM. Calls to set the class path after the JVM is started are silently ignored. If a jar must be loaded after the JVM is started, it may be loaded using ``java.net.URLClassLoader``. Classes loaded using a ``URLClassloader`` are not visible to JPype imports nor to JPackage. String conversions ------------------ The ``convertStrings`` argument defines how strings are returned by JPype. Early in the life of this project return types were often converted to Python types without regard to preserving the type information. Thus strings would automatically convert to a Python string effectively the data from Java to Python on each return. This was a violation of the Python philosophy that explicit is better than implicit. This also prohibited chaining of Java string operations as each operation would lose the Java representation and have to be transferred back and forth. The simple operation of trying to create a Java string was difficult as directly calling ``java.lang.String`` constructor would once again convert the result back to a Python string, hence the need to use the ``JString`` factory. There was an option to turn off the conversion of strings, but it was never operable. Therefore, all code written at the time would expect Java strings to convert to Python strings on return. Recognizing this is both a performance issue and that it made certain types of programming prohibitive, JPype switched to having a setting requiring applications to chose a policy at the start of operation. This option is a keyword argument ``convertStrings``. The default for 0.7 is to give the older broken behavior. If specified as False, Java strings will act as ordinary classes and return a Java string instance. This string instance can be converted by calling the Python ``str()`` function. Failure to specify a policy will issue a warning message. You are strongly encouraged to set convertStrings false especially when are writing reusable Python modules with JPype. String in JPype 0.8, the default will to not convert strings. Path to the JVM --------------- In order the start the JVM, JPype requires the path to the Java shared library typically located in the JRE installation. This can either be specified manually as the first argument to ``jpype.startJVM`` or by automatic search. The automatic search routine uses different mechanisms depending on the platform. Typically the first mechanism is the use the environment variable ``JAVA_HOME``. If no suitable JVM is found there, it will then search common directories based on the platform. On windows it will consult the registry. You can get the JVM found during the automatic search by calling ``jpype.getDefaultJVMPath()``. In order to use the JVM, the architecture of the JVM must match the Python version. A 64 bit Python can only use a 64 bit JVM. If no suitable JVM can be found it should raise an error. In some cases so rare, it may lead to a crash depending on how the platform handles a failed shared library load. Launching the JVM ----------------- Now that we have discussed the JVM options, lets show how to put it into practice. Suppose that the Python script at the top level of your working director, with a subdirectory holding all your working jars ``./lib``, and a second directory with bare classes ``./classes``. Java has been properly installed with the same architecture as Python (both 64 bit in this case). To start JPype we would execute the following: .. code-block:: python import jpype jpype.startJVM("-ea", classpath=['lib/*', 'classes'], convertStrings=False) Arguments that begin with a dash are passed to the JVM. Any unrecognized argument will raise an exception unless the keyword argument ``ignoreUnrecognized`` is set to ``True``. Details of available arguments can be found in the vendor JVM documentation. The most frequent problem encountered when starting JPype is the jars failing to be loaded. Java is unforgiving when loading jar files. To debug the failures, we will need to print the loaded classpath. Java has a method to retrieve the classpath that was used during the loading process. .. code-block:: python print(java.lang.System.getProperty('java.class.path')) This command will print the absolute path to each of the jars that will be used by the JVM. Each of the jars are written out explicitly as the JVM does not permit wild-cards. JPype has expanded each of them using `glob`. If an expected jar file is missing the list, then it will not be accessable. There is a flag to determine the current state of the JVM. Calling ``jpype.isJVMStarted()`` will return the current state of the JVM. Once the JVM is started, we can find out the version of the JVM. The JVM can only load jars and classfiles compiled for the JVM version or older. Newer jar files will invariably fail to load. The JVM version can be determined using ``jpype.getJVMVersion()``. .. _shutdownJVM: Shutting down the JVM ===================== At the other end of the process after all work has been performed, we will want to shutdown the JVM to terminate the program. This will happen automatically and no user intervention is required. If however, the user wants to continue execution of Python code after the JVM is finished they can explicitly call ``jpype.shutdownJVM()``. This can only be called from the main Python thread. Any other thread will raise an exception. The shutdown procedure of JPype and Java is fairly complicated. 1) JPype requests that the JVM shutdown gracefully. 2) Java waits until all non-daemon thread terminate. Thus if you did not send a termination to each non-daemon threads the shutdown will wait here until those threads complete their work. 3) Once the all threads have completed except for the main thread, the JVM will begin the shutdown sequence. From this point on the JVM is in a crippled state limited what can happen to spawning the shutdown threads and completing them. 4) The shutdown will first spawn the threads of cleanup routine that was attached to the JVM shutdown hook in arbitrary order. These routines can call back to Python and perform additional tasks. 5) Once the last of these threads are completed, JPype then shuts down the reference queue which dereferences held all Python resources. 6) Then JPype shuts down the type manager and frees all internal resources in the JPype module. 7) Last, it unloads the JVM shared library returning the memory used by the JVM. 8) Once that is complete, control is returned to Python. All Java objects are now considered dead and cannot be reactivated. Any attempt to access their data field will raise an exception. Attaching a shutdown hook ------------------------- If you have resources that need to be closed when the JVM is shutdown these should be attached to the Java Runtime object. The following pattern is used: .. code-block:: python @JImplements(Runnable) class MyShutdownHook: @JOverride def run(self): # perform any required shutdown activities java.lang.Runtime.getRuntime().addShutdownHook(Thread(MyShutdownHook())) This thread will be executed in a new thread once the main thread is the only one remaining alive. Care should always be taken to complete work in a timely fashion and be aware the shutdown threads are inherently racing with each other to complete their work. Thus try to avoid expensive operations on shutdown.. Debugging shutdown ------------------- The most common failure during shutdown is the failure of an attached thread to terminate. There are specific patterns in Java that allow you to query for all currently attached threads. Customization ************* JPype supports three different types of customizations. The first is to adding a Python base class into a Java tree as was done with certain exceptions. This type of customization required private calls in JPype and is not currently exposed to the user. Second a Python class can be used as a template when a Java class is first constructed to add additional functionality. This type of customization can be used to make a Java class appear as a native Python class. Many of the Java collection classes have been customized to match Python collections. Last, Python class can be added to the implicit conversion list. This customizer is used to make Python types compatable with Java without requiring the user to manually case over and over. All customization available to the users is done through class decorators added to Python classes or functions. .. _@JImplementationFor: .. _@JOverride: Class Customizers ================= Java wrappers can be customized to better match the expected behavior in Python. Customizers are defined using decorators. Applying the annotations ``@JImplementationFor`` and ``@JOverride`` to a regular Python class will transfer methods and properties to a Java class. ``@JImplementationFor`` requires the class name as a string, a Java class wrapper, or Java class instance. Only a string can be used prior to starting the JVM. ``@JOverride`` when applied to a Python method will hide the Java implementationallowing the Python method to replace the Java implementation. when a Java method is overridden, it is renamed with an proceeding underscore to appear as a private method. Optional arguments to ``@JOverride`` can be used to control the renaming and force the method override to apply to all classes that derive from a base class ("sticky"). Generally speaking, a customizer should be defined before the first instance of a given class is created so that the class wrapper and all instances will have the customization. Example taken from JPype ``java.util.Map`` customizer: .. code-block:: python @_jcustomizer.JImplementationFor('java.util.Map') class _JMap: def __jclass_init__(self): Mapping.register(self) def __len__(self): return self.size() def __iter__(self): return self.keySet().iterator() def __delitem__(self, i): return self.remove(i) The name of the class does not matter for the purposes of customizer though it should be a private class so that it does not get used accidentally. The customizer code will steal from the prototype class rather than acting as a base class, thus, ensuring that the methods will appear on the most derived Python class and are not hidden by the java implementations. The customizer will copy methods, callable objects, ``__new__``, class member strings, and properties. .. _@JConversion: Type Conversion Customizers =========================== One can add a custom converter method which is called whenever a specified Python type is passed to a particular Java type. To specify a conversion method add ``@JConversion`` to an ordinary Python function with the name of Java class to be converted to and one keyword of ``exact`` or ``instanceof``. The keyword controls how strictly the conversion will be applied. ``exact`` is restricted to Python objects whose type exactly matches the specified type. ``instanceof`` accepts anything that matches isinstance to the specified type or protocol. In some cases, the existing protocol definition will be overly broad. Adding the keyword argument ``excludes`` with a type or tuple of types can be used to prevent the conversion from being applied. Exclusions always apply first. User supplied conversions are tested after all internal conversions have been exhausted and are always considered to be an implicit conversion. .. code-block:: python @_jcustomizer.JConversion("java.util.Collection", instanceof=Sequence, excludes=str) def _JSequenceConvert(jcls, obj): return _jclass.JClass('java.util.Arrays').asList(obj) JPype supplies customizers for certain Python classes. ========================== ============================== Python class Implicit Java Class ========================== ============================== pathlib.Path java.io.File pathlib.Path java.nio.file.Path datetime.datetime java.time.Instant collections.abc.Sequence java.util.Collection collections.abs.Mapping java.util.Map ========================== ============================== Collections *********** JPype uses customizers to augment Java collection classes to operate like Python collections. Enhanced objects include ``java.util.List``, ``java.util.Set``, ``java.util.Map``, and ``java.util.Iterator``. These classes generally comply with the Python API except in cases where there is a significant name conflict and thus no special treatment is required when handling these Java types. Details of customizing Java classes can be found in the previous chapter, Customization_. This section will detail the various customization that are to applied the Java collection classes. Iterable ======== All Java classes that implement ``java.util.Iterable`` are customized to support Python iterator notation and thus can be used in Python for loops and in list comprehensions. Iterators ========= All Java classes that implement ``java.util.Iterator`` act as Python iterators. Collection ========== All Java classes that inherit from ``java.util.Collection`` have a defined length determined by the Python ``len(obj)`` function. As they also inherit from Iterable, they have iterator, forech traversal, and list comprehension. In addition, methods that take a Java collection can convert a Python sequence into a collection implicitly if all of the elements have a conversion into Java. Otherwise a ``TypeError`` is raised. .. _java.util.List: Lists ===== Java List classes such as ArrayList and LinkedList can be used in Python ``for`` loops and list comprehensions directly. A Java list can be converted to a Python list or the reverse by calling the requested type as a copy constructor. .. code-block:: python pylist = ['apple', 'orange', 'pears'] # Copy the Python list to Java. jlist = java.util.ArrayList(pylist) # Copy the Java list back to Python. pylist2 = list(jlist) Note that the individual list elements are still Java objects when converted to Python and thus a list comprehension would be required to force Python types if required. Converting to Java will attempt to convert each argument individually to Java. If there is no conversion it will produce a ``TypeError``. The conversion can be forced by casting to the appropriate Java type with a list comprehension or by defining a new conversion customizer. Lists also have iterable, length, item deletion, and indexing. Note that indexing of ``java.util.LinkedList`` is supported but can have a large performance penalty for large lists. Use of iteration is much for efficient. .. _java.util.Map: Map === A Java classes that implement ``java.util.Map`` inherit the Python collections.abc.Mapping interface. As such they can be iterated, support the indexing operator for value lookups, item deletion, length, and support contains. Here is a summary of their capabilities: =========================== ================================ Action Python =========================== ================================ Place a value in the map ``jmap[key]=value`` Delete an entry ``del jmap[key]`` Get the length ``len(jmap)`` Lookup the value ``v=jmap[key]`` Get the entries ``jmap.items()`` Fetch the keys ``jmap.key()`` Check for a key ``key in jmap`` =========================== ================================ In addition, methods that take a Java map can implicitly convert a Python ``dict`` or a class that implements ``collections.abc.Mapping`` assuming that all of the map entries can be converted to Java. Otherwise a ``TypeError`` is raised. MapEntry ======== Java map entries unpack into a two value tuple, thus supporting iterating through key value pairs. Thus is useful when iterating map entries in a for loop by pairs. Set === All Java classes that implement ``java.util.Set`` implement delitem as well as the Java collection customizations. Enumeration =========== All Java classes that implement ``java.util.Enumeration`` inherit Python iterator behavior and can be used in Python for loops and list comprehensions. Working with NumPy ****************** As one of the primary focuses of JPype is working with numerical codes such as NumPy, there are a number of NumPy specific enhancements. NumPy is a large binary package and therefore JPype cannot be compiled against NumPy directly without force it to be a requirement. Instead of compiling against NumPy directly, JPype implements interfaces that NumPy can recognize and use. The specific enhancements are the following: direct buffer transfers of primitive arrays and buffers, direct transfer of multi dimensional arrays, buffer backed NumPy arrays, and conversion of NumPy integer types to Java boxed types. Transfers to Java ================= Memory from a NumPy array can be transferred Java in bulk. The transfer of a one dimensional NumPy array to Java can either be done at initialization or by use of the Python slice operator. Assuming we have a single dimensional NumPy array ``npa``, we can transfer it with initialization using .. code-block:: python ja = JArray(JInt)(npa) Or we can transfer it to Java as a slice assignment. .. code-block:: python ja[:] = npa The slice operator can transfer the entire array or just a portion of it. Multidimensional transfers to Java ================================== Multidimensional arrays can also be transferred at initialization time. To transfer a NumPy array to Java use the ``JArray.of`` function .. code-block:: python z = np.zeros((5,10,20)) ja = JArray.of(z) Transfers to NumPy ================== Java arrays can be in two forms. Java multidimensional arrays are not contiguous in memory. If all of the arrays in each dimension are the same, then the array is rectangular. If the size of the arrays within any dimension differ, then the array is jagged. Jagged arrays are an array of arrays rather than a rectangular block of memory. NumPy arrays only hold rectangular arrays as multidimensional arrays of primitives. All other arrangements are a stored as a single dimensional array of objects. JPype can automatically transfer a rectangular array to NumPy as a bulk transfer. To do so JPype supports a ``memoryview`` on rectangular arrays. Whenever a memoryview is called on a multidimensional array of primitives, JPype verifies that it is rectangular and creates a buffer. If it is jagged, a ``BufferError`` is raised. When a Java array is used as an argument to initialize a NumPy array, it creates a ``memoryview`` so that all of the memory can be transferred in bulk. Buffer backed NumPy arrays ========================== Java direct buffers provide access between foreign memory and Java. This access bypasses the JNI layer entirely, permitting Java and Python to operate on a memory space with native speed. Java direct buffers are not under the control of the garbage collector and thus can result in memory leaks and memory exhaustion if not used carefully. This is used with Java libraries that support direct buffers. Direct buffers are part of the Java ``nio`` package and thus functionality for buffers is in ``jpype.nio``. To create a buffer backed NumPy array, the user must either create a direct memory buffer using the Java direct buffer API or create a Python ``bytearray`` and apply ``jpype.nio.convertToByteBuffer`` to map this memory into Java space. NumPy can then convert the direct buffer into an array using ``asarray``. To originate a direct buffer from Java, use: .. code-block:: python jb = java.nio.ByteBuffer.allocateDirect(80) db = jb.asDoubleBuffer() a = np.asarray(db) To origate a direct buffer from Python, use: .. code-block:: python bb = bytearray(80) jb = jpype.nio.convertToDirectBuffer(bb) db = jb.asDoubleBuffer() a = np.asarray(db) Buffer backed arrays have one downside. Python and by extension NumPy have no way to tell when a buffer becomes invalid. Once the JVM is shutdown, all buffers become invalid and any access to NumPy arrays backed by Java risk crashing. To avoid this fate, either create the memory for the buffer from within Python and pass it to Java. Or use the Java ``java.lang.Runtime.exit`` which will terminate both the Java and Python process without leaving any opertunity to access a dangling buffer. Buffer backed memory is not limited to use with NumPy. Buffer transfers are supported to provide shared memory between processes or memory mapped files. Anything that can be mapped to an address with as a flat array of primitives with machine native byte ordering can be mapped into Java. NumPy Primitives ================ When converting a Python type to a boxed Java type, there is the difficulty that Java has no way to known the size of a Python numerical value. But when converting NumPy numerical types, this is not an issue. The following conversions apply to NumPy primitive types. =========== ======================= Numpy Type Java Boxed Type =========== ======================= np.int8 java.lang.Byte np.int16 java.lang.Short np.int32 java.lang.Integer np.int64 java.lang.Long np.float32 java.lang.Float np.float64 java.lang.Double =========== ======================= Further, these NumPy types obey Java type conversion rules so that they act as the equivalent of the Java primitive type. .. _Proxies: Implementing Java interfaces **************************** Proxies in Java are foreign elements that pretend to implement a Java interface. We use this proxy API to allow Python to implement any Java interface. Of course, a proxy is not the same as subclassing Java classes in Python. However, most Java APIs are built so that sub-classing is not required. Good examples of this are AWT and SWING. Except for relatively advanced features, it is possible to build complete UIs without creating a single subclass. For those cases where sub-classing is absolutely necessary (i.e. using Java's SAXP classes), it is necessaryy to create an interface and a simple subclass in Java that delegates the calls to that interface. The interface can then be implemented in Python using a proxy. There are two APIs for supporting of Java proxies. The new high-level interface uses decorators which features strong error checking and easy notation. The older low-level interface allows any Python object or dictionary to act as a proxy even if it does not provide the required methods for the interface. .. _@JImplements: Implements ========== The newer style of proxy works by decorating any ordinary Python class to designate it as a proxy. This is most effective when you control the Python class definition. If you don't control the class definition you either need to encapsulate the Python object in another object or use the older style. Implementing a proxy is simple. First construct an ordinary Python class with method names that match the Java interface to be implemented. Then add the ``@JImplements`` decorator to the class definition. The first argument to the decorator is the interface to implement. Then mark each method corresponding to a Java method in the interface with ``@JOverride``. When the proxy class is declared, the methods will be checked against the Java interface. Any missing method will result in JPype raising an exception. High-level proxies have one other important behavior. When a proxy created using the high-level API returns from Java it unpacks back to the original Python object complete with all of its attributes. This occurs whether the proxy is the ``self`` argument for a method or proxy is returned from a Java container such as a list. This is accomplished because the actually proxy is a temporary Java object with no substance, thus rather than returning a useless object, JPype unpacks the proxy to its original Python object. Proxy Method Overloading ------------------------ Overloaded methods will issue to a single method with the matching name. If they take different numbers of arguments then it is best to implement a method dispatch: .. code-block:: python @JImplements(JavaInterface) class MyImpl: @JOverride def callOverloaded(self, *args): # always use the wild card args when implementing a dispatch if len(args)==2: return self.callMethod1(*args) if len(args)==1 and isinstance(args[0], JString): return self.callMethod2(*args) raise RuntimeError("Incorrect arguments") def callMethod1(self, a1, a2): # ... def callMethod2(self, jstr): # ... Multiple interfaces ------------------- Proxies can implement multiple interfaces as long as none of those interfaces have conflicting methods. To implement more than one interface, use a list as the argument to the JImplements decorator. Each interface must be implemented completely. Deferred realization -------------------- Sometimes it is useful to implement proxies before the JVM is started. To achieve this, specify the interface using a string and add the keyword argument ``deferred`` with a value of ``True`` to the decorator. .. code-block:: python @JImplements("org.foo.JavaInterface", deferred=True) class MyImpl: # ... Deferred proxies are not checked at declaration time, but instead at the time for the first usage. Because of this, when uses an deferred proxy the code must be able to handle initialization errors wherever the proxy is created. Other than the raising of exceptions on creation, there is no penalty to deferring a proxy class. The implementation is checked once on the first usage and cached for the remaining life of the class. Proxy Factory ============= When a foreign object from another module for which you do not control the class implementation needs to be passed into Java, the low level API is appropriate. In this API you manually create a JProxy object. The proxy object must either be a Python object instance or a Python dictionary. Low-level proxies use the JProxy API. JProxy ------ The ``JProxy`` allows Python code to "implement" any number of Java interfaces, so as to receive callbacks through them. The JProxy factory has the signature:: JProxy(intr, [dict=obj | inst=obj] [, deferred=False]) The first argument is the interface to be implemented. This may be either a string with the name of the interface, a Java class, or a Java class instance. If multiple interfaces are to be implemented the first argument is replaced by a Python sequence. The next argument is a keyword argument specifying the object to receive methods. This can either be a dictionary ``dict`` which names the methods as keys or an object instance ``inst`` which will receive method calls. If more than one option is selected, a ``TypeError`` is raised. When Java calls the proxy the method is looked up in either the dictionary or the instance and the resulting method is called. Any exceptions generated in the proxy will be wrapped as a ``RuntimeException`` in Java. If that exception reaches back to Python it is unpacked to return the original Python exception. Assume a Java interface like: .. code-block:: java public interface ITestInterface2 { int testMethod(); String testMethod2(); } You can create a proxy *implementing* this interface in two ways. First, with an object: .. code-block:: python class C : def testMethod(self) : return 42 def testMethod2(self) : return "Bar" c = C() # create an instance proxy = JProxy("ITestInterface2", inst=c) # Convert it into a proxy or you can use a dictionary. .. code-block:: python def _testMethod() : return 32 def _testMethod2() : return "Fooo!" d = { 'testMethod' : _testMethod, 'testMethod2' : _testMethod2, } proxy = JProxy("ITestInterface2", dict=d) Proxying Python objects ======================= Sometimes it is necessary to push a Python object into Java memory space as an opaque object. This can be achieved using be implementing a proxy for an interface which has no methods. For example, ``java.io.Serializable`` has no arguments and little functionality beyond declaring that an object can be serialized. As low-level proxies to not automatically convert back to Python upon returning to Java, the special keyword argument ``convert`` should be set to True. For example, let's place a generic Python object such as NumPy array into Java. .. code-block:: python import numpy as np u = np.array([[1,2],[3,4]]) ls = java.util.ArrayList() ls.add(jpype.JProxy(java.io.Serializable, inst=u, convert=True)) u2 = ls.get(0) print(u is u2) # True! We get the expected result of ``True``. The Python has passed through Java unharmed. In future versions of JPype, this method will be extended to provide access to Python methods from within Java by implementing a Java interface that points to back to Python objects. Reference Loops =============== It is strongly recommended that object used in proxies must never hold a reference to a Java container. If a Java container is asked to hold a Python object and the Python object holds a reference to the container, then a reference loop is formed. Both the Python and Java garbage collectors are aware of reference loops within themselves and have appropriate handling for them. But the memory space of the other machine is opaque and neither Java nor Python is aware of the reference loop. Therefore, unless you manually break the loop by either clearing the container, or removing the Java reference from Python these objects can never be collected. Once you lose the handle they will both become immortal. Ordinarily the proxy by itself would form a reference loop. The Python object points to a Java invocation handler and the invocation handler points back to Python object to prevent the Python object from going away as long as Java is holding onto the proxy. This is resolved internally by making the Python weak reference the Java portion. If Java ever garbage collects the Java half, it is recreated again when the proxy is next used. This does have some consequences for the use of proxies. Proxies must never be used as synchronization objects. Whenever they are garbage collected, they lose their identity. In addition, their hashCode and system id both are reissued whenever they are refreshed. Therefore, using a proxy as a Java map key can be problematic. So long as it remains in the Java map, it will maintain the same identify. But once it is removed, it is free to switch identities every time it is garbage collected. AWT/Swing ********* Java GUI elements can be used from Python. To use Swing elements the event loop in Java must be started from a user thread. This will prevent the JVM from shutting down until the user thread is completed. Here is a simple example which creates a hello world frame and launches it from within Python. .. code-block:: python import jpype import jpype.imports jpype.startJVM() import java import javax from javax.swing import * def createAndShowGUI(): frame = JFrame("HelloWorldSwing") frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE) label = JLabel("Hello World") frame.getContentPane().add(label) frame.pack() frame.setVisible(True) # Start an event loop thread to handling gui events @jpype.JImplements(java.lang.Runnable) class Launch: @jpype.JOverride def run(self): createAndShowGUI() javax.swing.SwingUtilities.invokeLater(Launch()) Concurrent Processing ********************* This chapter covers the topic of threading, synchronization, and multiprocess. Much of this material depends on the use of Proxies_ covered in the prior chapter. Threading ========= JPype supports all types of threading subject to the restrictions placed by Python. Java is inherently threaded and support a vast number of threading styles such as execution pools, futures, and ordinary thread. Python is somewhat more limited. At its heart Python is inherently single threaded and requires a master lock known as the GIL (Global Interpreter Lock) to be held every time a Python call is made. Python threads are thus more cooperative that Java threads. To deal with this behavior, JPype releases the GIL every time it leaves from Python into Java to any user defined method. Shorter defined calls such as to get a string name from from a class may not release the GIL. Every time the GIL is released it is another opportunity for Python to switch to a different cooperative thread. Python Threads -------------- For the most part, Python threads based on OS level threads (i.e. POSIX threads) will work without problem. The only challenge is how Java sees threads. In order to operate on a Java method, the calling thread must be attached to Java. Failure to attach a thread will result in a segmentation fault. It used to be a requirement that users manually attach their thread to call a Java function, but as the user has no control over the spawning of threads by other applications such as an IDE, this inevitably lead to unexpected segmentation faults. Rather that crashing randomly, JPype automatically attachs any thread that invokes a Java method. These threads are attached automatically as daemon threads so that will not prevent the JVM from shutting down properly upon request. If a thread must be attached as a non-daemon, use the method ``java.lang.Thread.attach()`` from within the thread context. Once this is done the JVM will not shut down until that thread is completed. There is a function called ``java.lang.Thread.isAttached()`` which will check if a thread is attached. As threads automatically attach to Java, the only way that a thread would not be attached is if it has never called a Java method. The downside of automatic attachment is that each attachment allocates a small amount of resources in the JVM. For applications that spawn frequent dynamically allocated threads, these threads will need to be detached prior to completing the thread with ``java.lang.Thread.detach()``. When implementing dynamic threading, one can detach the thread whenever Java is no longer needed. The thread will automatically reattach if Java is needed again. There is a performance penalty each time a thread is attached and detached. Java Threads ------------ To use Java threads, create a Java proxy implementins ``java.lang.Runnable``. The Runnable can then be passed any Java threading mechanism to be executed. Each time that Java threads transfer control back to Python, the GIL is reacquired. Other Threads ------------- Some Python libraries offer other kinds of thread, (i.e. microthreads). How they interact with Java depends on their nature. As stated earlier, any OS- level threads will work without problem. Emulated threads, like microthreads, will appear as a single thread to Java, so special care will have to be taken for synchronization. .. _synchronized: Synchronization =============== Java synchronization support can be split into two categories. The first is the ``synchronized`` keyword, both as prefix on a method and as a block inside a method. The second are the three methods available on the Object class (``notify, notifyAll, wait``). To support the ``synchronized`` functionality, JPype defines a method called ``synchronized(obj)`` to be used with the Python ``with`` statement, where obj has to be a Java object. The return value is a monitor object that will keep the synchronization on as long as the object is kept alive. For example, .. code-block:: python from jpype import synchronized mySharedList = java.util.ArrayList() # Give the list to another thread that will be adding items otherThread,setList(mySharedList) # Lock the list so that we can access it without interference with synchronized(mySharedList): if not mySharedList.isEmpty(): ... # process elements # Resource is unlocked once we leave the block The Python ``with`` statement is used to control the scope. Do not hold onto the monitor without a ``with`` statement. Monitors held outside of a ``with`` statement will not be released until they are broken when the monitor is garbage collected. The other synchronization methods are available as-is on any Java object. However, as general rule one should not use synchronization methods on Java String as internal string representations may not be complete objects. For synchronization that does not have to be shared with Java code, use Python's support directly rather than Java's synchronization to avoid unnecessary overhead. Threading examples ================== Java provides a very rich set of threading tools. This can be used in Python code to extend many of the benefits of Java into Python. However, as Python has a global lock, the performance of Java threads while using Python is not as good as native Java code. Limiting execution time ----------------------- We can combine proxies and threads to produce achieve a number of interesting results. For example: .. code-block:: python def limit(method, timeout): """ Convert a Java method to asynchronous call with a specified timeout. """ def f(*args): @jpype.JImplements(java.util.concurrent.Callable) class g: @jpype.JOverride def call(self): return method(*args) future = java.util.concurrent.FutureTask(g()) java.lang.Thread(future).start() try: timeunit = java.util.concurrent.TimeUnit.MILLISECONDS return future.get(int(timeout*1000), timeunit) except java.util.concurrent.TimeoutException as ex: future.cancel(True) raise RuntimeError("canceled", ex) return f print(limit(java.lang.Thread.sleep, timeout=1)(200)) print(limit(java.lang.Thread.sleep, timeout=1)(20000)) Here we have limited the execution time of a Java call. Multiprocessing =============== Because only one JVM can be started per process, JPype cannot be used with processes created with ``fork``. Forks copy all memory including the JVM. The copied JVM usually will not function properly thus JPype cannot support multiprocessing using fork. To use multiprocessing with JPype, processes must be created with "spawn". As the multiprocessing context is usually selected at the start and the default for Unix is fork, this requires the creating the appropriate spawn context. To launch multiprocessing properly the following recipe can be used. .. code-block:: python import multiprocessing as mp ctx = mp.get_context("spawn") process = ctx.Process(...) queue = ctx.Queue() # ... When using multiprocessing, Java objects cannot be sent through the default Python ``Queue`` methods as calls pickle without any Java support. This can be overcome by wrapping Python ``Queue`` to first encode to a byte stream using the JPickle package. By wrapping a ``Queue`` with the Java pickler any serializable Java object can be transferred between processes. In addition, a standard Queue will not produce an error if is unable to pickle a Java object. This can cause deadlocks when using multiprocessing IPC, thus wrapping any Queue is required. Miscellaneous topics ******************** This chapter contains all the stuff that did not fit nicely into the narrative about JPype. Topics include code completion, performance, debugging Java within JPype, debugging JNI and other JPype failures, how caller sensitive methods are dealt with, and finally limitations of JPype. Javadoc ======= JPype can display javadoc in ReStructured Text as part of the Python documentation. To access the javadoc, the javadoc package must be located on the classpath. This includes the JDK package documentation. For example to get the documentation for ``java.lang.Class``, we start the JVM with the JDK documentation zip file on the classpath. .. code-block: java import jpype jpype.startJVM(classpath='jdk-11.0.7_doc-all.zip') We can then access the java docs for the String with ``help(java.lang.String)`` or for the methods with ``help(java.lang.String.trim)``. To use the javadoc supplied by a third party include the both the jar and javadoc in the classpath. .. code-block: java import jpype jpype.startJVM(classpath=['gson-2.8.5.jar', 'gson-2.8.5-javadoc.jar']) The parser will ignore any javadoc which cannot be extracted. It has some robustness against tags that are not properly closed or closed twice. Javadoc with custom page layouts will likely not be extracted. If javadoc for a class cannot be located or extracted properly, default documentation will be generated using Java reflection. Autopep8 ======== When Autopep8 is applied a Python script, it reorganizes the imports to conform to E402_. This has the unfortunate side effect of moving the Java imports above the startJVM statement. This can be avoided by either passing in ``--ignore E402`` or setting the ignore in ``.pep8``. .. _E402: https://www.flake8rules.com/rules/E402.html Example: .. code-block:: python import jpype import jpype.imports jpype.startJVM() from gov.llnl.math import DoubleArray Result without ``--ignore E402`` .. code-block:: python from gov.llnl.math import DoubleArray # Fails, no JVM running import jpype import jpype.imports jpype.startJVM() Performance =========== JPype uses JNI, which is well known in the Java world as not being the most efficient of interfaces. Further, JPype bridges two very different runtime environments, performing conversion back and forth as needed. Both of these can impose performance bottlenecks. JNI is the standard native interface for most, if not all, JVMs, so there is no getting around it. Down the road, it is possible that interfacing with CNI (GCC's Java native interface) may be used. Right now, the best way to reduce the JNI cost is to move time critical code over to Java. Follow the regular Python philosophy : **Write it all in Python, then write only those parts that need it in C.** Except this time, it's write the parts that need it in Java. Everytime an object is passed back and forth, it will incure a conversion cost.. In cases where a given object (be it a string, an object, an array, etc ...) is passed often into Java, the object should be converted once and cached. For most situations, this will address speed issues. To improve speed issues, JPype has converted all of the base classes into CPython. This is a very significant speed up over the previous versions of the module. In addition, JPype provides a number of fast buffer transfer methods. These routines are triggered automatically working with any buffer aware class such as those in NumPy. As a final note, while a JPype program will likely be slower than its pure Java counterpart, it has a good chance of being faster than the pure Python version of it. The JVM is a memory hog, but does a good job of optimizing code execution speeds. Code completion =============== Python supports a number of different code completion engines that are integrated in different Python IDEs. JPype has been tested with both the IPython greedy completion engine and Jedi. Greedy has the disadvantage that is will execute code resulting potentially resulting in an undesirable result in Java. JPype is Jedi aware and attempts to provide whatever type information that is available to Jedi to help with completion tasks. Overloaded methods are opaque to Jedi as the return type cannot be determined externally. If all of the overloads have the same return type, the JPype will add the return type annotation permitting Jedi to autocomplete through a method return. For example: .. code-block:: python JString("hello").substring.__annotations__ # Returns {'return': } Jedi can manually be tested using the following code. .. code-block:: python js = JString("hello") src = 'js.s' script = jedi.Interpreter(src, [locals()]) compl = [i.name for i in script.completions()] This will produce a list containing all method and field that begin with the letter "s". JPype has not been tested with other autocompletion engines such as Kite. Garbage collection ================== Garbage collection (GC) is supposed to make life easier for the programmer by removing the need to manually handle memory. For the most part it is a good thing. However, just like running a kitchen with two chiefs is a bad idea, running with two garbage collections is also bad. In JPype we have to contend with the fact that both Java and Python provide garbage collection for their memory and neither provided hooks for interacting with an external garbage collector. For example, Python is creating a bunch a handles to Java memory for a period of time but they are in a structure with a reference loop internal to Python. The structures and handles are small so Python doesn't see an issue, but each of those handles is holding 1M of memory in Java space. As the heap fills up Java begins garbage collecting, but the resources can't be freed because Python hasn't cleanup up these structures. The reverse occurs if a proxy has any large NumPy arrays. Java doesn't see a problem as it has plenty of space to work in but Python is running its GC like mad trying to free up space to work. To deal with this issue, JPype links the two garbage collectors. Python is more aggressive in calling GC than Java and Java is much more costly than Python in terms of clean up costs. So JPype manages the balance. JPype installs a sentinel object in Java. Whenever that sentinel is collected Java is running out of space and Python is asked to clean up its space as well. The reverse case is more complicated as Python can't just call Java's expensive routine any time it wants. Instead JPype maintains a low-water and high-water mark on Python owned memory. Each time it nears a high-water mark during a Python collection, Java GC gets called. If the water level shrinks than Java was holding up Python memory and the low-water mark is reset. Depending on the amount of memory being exchanged the Java GC may trigger as few as once every 50 Python GC cycles or as often as every other. The sizing on this is dynamic so it should scale to the memory use of a process. Using JPype for debugging Java code =================================== One common use of JPype is to function as a Read-Eval-Print Loop for Java. When operating Java though Python as a method of developing or debugging Java there are a few tricks that can be used to simplify the job. Beyond being able to probe and plot the Java data structures interactively, these methods include: 1) Attaching a debugger to the Java JVM being run under JPype. 2) Attaching debugging information to a Java exception. 3) Serializing the state of a Java process to be evaluated at a later point. We will briefly discuss each of these methods. Attaching a Debugger -------------------- Interacting with Java through a shell is great, but sometimes it is necessary to drop down to a debugger. To make this happen we need to start the JVM with options to support remote debugging. We start the JVM with an agent which will provide a remote debugging port which can be used to attach your favorite Java debugging tool. As the agent is altering the Java code to create additional debugging hooks, this process can introduce additional errors or alter the flow of the code. Usually this is used by starting the JVM with the agent, placing a pause marker in the Python code so that developer can attach the Java debugger, executing the Python code until it hits the pause, attaching the debugger, setting break point in Java, and then asking Python to proceed. So lets flesh out the details of how to accomplish this... .. code-block:: python jpype.startJVM("-Xint", "-Xdebug", "-Xnoagent", "-Xrunjdwp:transport=dt_socket,server=y,address=12999,suspend=n") Next, add a marker in the form of a pause statement at the location where the debugger should be attached. .. code-block:: python input("pause to attach debugger") myobj.callProblematicMethod() When Python reaches that point during execution, switch to a Java IDE such as NetBeans and select Debug : Attach Debugger. This brings up a window (see example below). After attaching (and setting desired break points) go back to Python and hit enter to continue. NetBeans should come to the foreground when a breakpoint is hit. .. image:: attach_debugger.png Attach data to an Exception --------------------------- Sometimes getting to the level of a debugger is challenging especially if the code is large and error occurs rarely. In this case, it is often beneficial to attach data to an exception. To achieve this, we need to write a small utility class. Java exceptions are not strictly speaking expandable, but they can be chained. Thus, it we create a dummy exception holding a ``java.util.Map`` and attach it to as the cause of the exception, it will be passed back down the call stack until it reaches Python. We can then use ``getCause()`` to retrieve the map containing the relevant data. Capturing the state ------------------- If the program is not running in an interactive shell or the program run time is long, we may not want to deal with the problem during execution. In this case, we can serialize the state of the relevant classes and variables. To use this option, we mus make sure all of the classes in Java that we are using are ``Serializable``. Then add a condition that detects the faulty algorithm state. When the fault occurs, create a ``java.util.HashMap`` and populate it with the values to be examined from within Python. Use serialization to write the entire structure to a file. Execute the program and collect all of the state files. Once the state files have been collected, start Python with an interactive shell and launch JPype with a classpath for the jars. Finally, deserialize the state files to access the Java structures that have been recorded. Getting additional diagnostics ============================== For the most part JPype does what its told, but that does not mean that there are no bugs. With some many different interactions between Python and Java there is always some untested edge-cases. JPype has a few diagnostic tools to help deal with these sorts of problems but each of them require accessing a "private" JPype symbol which may be altered, removed, folded, spindled, or mutilated in any future release. Thus none of the following should be used in production code. Checking the type of a cast --------------------------- Sometimes it is difficult to understand why a particular method overload is being selected by the method dispatch. To check the match type for a conversion call the private method ``Class._canConvertToJava``. This will produce a string naming the type of conversion that will be performed as one of ``none``, ``explicit``, ``implicit``, or ``exact``.. To test the result of the conversion process, call ``Class._convertToJava``. Unlike an explicit cast, this just attempts to perform the conversion without bypassing all of the other logic involved in casting. It replicates the exact process used when a method is called or a field is set. C++ Exceptions in JPype ----------------------- Internally JPype can generate C++ exception which is converted into Python exceptions for the user. To trace an error back to its C++ source, it is necessary to obtain the original C++ exception. As all sensitive block have function names compiled in to the try catch blocks, these C++ exception stack frames can be extracted as the "cause" of a Python exception. To enable C++ stack traces use the command ``_jpype.enableStacktraces(True)``. Once executed all C++ exceptions that fell through a C++ exception handling block will produce an augmented C++ stack trace. If the JPype source code is available to Python, it can even print out each line where the stack frame was caught. This is usually at the end of each function that was executed. JPype does not need to be recompiled to use this option. Tracing ------- To debug a problem that resulted from a stateful interaction of elements the use of the JPype tracing mode may helpful. To enable tracing recompile JPype with the ``--enable-tracing`` mode set. When code is executed with tracing, every JNI call along with the object addresses and exceptions will be printed to the console. This is keyed to macros that appear at the start and end of each JPype function. These macros correspond to a try catch block. This will often produce very large and verbose tracing logs. However, tracing is often the only way to observe a failure that originated in one JNI call but did not fail until many calls later. Instrumentation --------------- In order to support coverage tools, JPype can be compiled with a special instrumentation mode in which the private module command ``_jpype.fault`` can be used to trigger an error. The argument to the fault must be a function name as given in the ``JP_TRACE_IN`` macro at the start of each JPype function or a special trigger point defined in the code. When the fault point is encounter it will trigger a ``SystemError``. This mode of operation can be used to replicate the path that a particular call took and verify that the error handling from that point back to Java is safe. Because instrumentation uses the same control hooks as tracing, only one mode can be active at a time. Enabling instrumentation requires recompiling the JPype module with ``--enable-coverage`` option. Using a debugger ---------------- If there is a crash in the JPype module, it may be necessary to get a backtrace using a debugger. Unfortunately Java makes this task a bit complicated. As part of its memory handling routine, Java takes over the segmentation fault handler. Whenever the fault is triggered, Java checks to see if it was the result the growth of an internal structure. If it was simply a need for additional space, Java handles the exception by allocating addition memory. On the other hand, if a fault was triggered by some external source, Java constructs a JVM fault report and then transfers control back to the usual segmentation fault handler. Java will often corrupt the stack frame. Any debugger attempting to unpack the corrupted core file will instead get random function addresses. The alternative is for the user to start JPype with an interactive debugger and execute to the fault point. But this option also presents challenges. The first action after starting the JVM is a test to see if its segmentation fault handler was installed properly. Thus it will trigger an intentional segmentation fault. The debugger can not recognize the difference between an intentional test and an actual fault, so the test will stop the debugger. To avoid this problem debuggers such as gdb must be set to ignore the first segmentation fault. Further details on this can be found in the developer guide. .. _caller sensitive: Caller sensitive methods ======================== The Java security model tracks what caller requested the method as a means to determine the level of access to provide. Internal callers are provided privileged access to perform unsafe operations and external callers are given safer and more restricted access. To perform this task, the JVM seaches the call stack to obtain the calling methods module. This presents a difficulty for method invoked from JNI. A method called from JNI lacks any call stack to unravel. Rather than relegating the call to a safer level of access, the security model would outright deny access to certain JPype calls. This resulted in a number of strange behaviors over the years that were forced to be worked around. This issue was finally solved with the release of Java 12 when they outright broken all calls to getMethod by throwing a NullPointer exception whenever the caller frame was not found. This inadvertent clued us into why Java would act so strangely for certain calls such as constructing a SQL database or attempting to call ``Class.forName``. By creating an actual test case to work around we were able to resolve this limitation. Once we identified the issue, the workaround is only call caller sensitive methods from within Java. But given that we call methods through JNI and the JNI interface defines no way to specify an origin for the call, the means we needed to develop an alternative calling mechanism. Instead of calling methods directly, we instead pass the method id and the list of desired arguments to the internal ``org.jpype`` Java package. This package unpacks the request and executes the desired method from within Java. The call stack will indicate the caller is an external jar and be given the safe and restricted level of access. The result is then passed back to through the JNI layer. This special calling mechanism is slower and more indirect than the normal calling procedure, so its use is limited to only those methods that really require a caller sensitive procedure. The mechanism to determine which methods are caller sensitive depends on the internals of Java and have changed with Java versions. Older Java versions did not directly mark the caller sensitive methods and we must instead blanket bomb all methods belonging to ``java.lang.Class``, ``java.lang.ClassLoader``, and ``java.sql.DriverManager``. Newer versions specifically annotate the methods requiring caller sensitive treatment, but for some reason this annotation is a package private and thus we must search through method annotations by name to find the caller sensitive annotation. Fortunately, this process is only performed once when the class is created, and very few methods have a large number of annotations so this isn't a performance hit. .. _limitations: JPype Known limitations ======================= This section lists those limitations that are unlikely to change, as they come from external sources. Restarting the JVM ------------------- JPype caches many resources to the JVM. Those resource are still allocated after the JVM is shutdown as there are still Python objects that point to those resources. If the JVM is restarted, those stale Python objects will be in a broken state and the new JVM instance will obtain the references to these resulting in a memory leak. Thus it is not possible to start the JVM after it has been shut down with the current implementation. Running multiple JVM -------------------- JPype uses the Python global import module dictionary, a global Python to Java class map, and global JNI TypeManager map. These resources are all tied to the JVM that is started or attached. Thus operating more than one JVM does not appear to be possible under the current implementation. Further, as of Java 1.2 there is no support for creating more than one JVM in the same process. Difficulties that would need to be overcome to remove this limitation include: - Finding a JVM that supports multiple JVMs running in the same process. This can be achieved on some architectures by loading the same shared library multiple times with different names. - Alternatively as all available JVM implementations support on one JVM instance per process, a communication layer would have to proxy JNI class from JPype to another process. But this has the distinct problem that remote JVMs cannot register native methods nor share memory without considerable effort. - Which JVM would a static class method call. The class types would need to be JVM specific (ie. ``JClass('org.MyObject', jvm=JVM1)``) - How would a wrapper from two different JVM coexist in the ``jpype._jclass`` module with the same name if different class is required for each JVM. - How would the user specify which JVM a class resource is created in when importing a module. - How would objects in one JVM be passed to another. - How can boxed and String types hold which JVM they will box to on type conversion. Thus it appears prohibitive to support multiple JVMs in the JPype class model. Errors reported by Python fault handler --------------------------------------- The JVM takes over the standard fault handlers resulting in unusual behavior if Python handlers are installed. As part of normal operations the JVM will trigger a segmentation fault when starting and when interrupting threads. Pythons fault handler can intercept these operations and interpret these as real faults. The Python fault handler with then reporting extraneous fault messages or prevent normal JVM operations. When operating with JPype, Python fault handler module should be disabled. This is particularly a problem for running under pytest as the first action it performs is to take over the error handlers. This can be disabled by adding this block as a fixture at the start of the test suite. .. code-block:: python try: import faulthandler faulthandler.enable() faulthandler.disable() except: pass This code enables fault handling and then returns the default handlers which will point back to those set by Java. Python faulthandlers can also interfer with the JIT compiler. The Java Just-In-Time (JIT) compiler determines when a portion of code needs to be compiled into machine code to improve performance. When it does, it triggers either a SEGSEGV or SEGBUS depending on the machine architecture which breaks out any threads which are currently executing the existing code. Because the JIT compiler self triggers, this will cause a failure to appear in a call which worked earlier in the execution without an issue. If the Python fault handler interrupts this process, it will produce a "Fatal Python Error:" followed by either SIGSEGV or SEGBUS. This error message then fails to hit the needed Java handler resulting in a crash. This message will disappear if the JIT compiler is disabled with the option "-Xint". Running without the JIT compiler creates a severe performance penalty so disabling the fault handler should be the preferred solution. Some modules such as Abseil Python Common Libraries (absl) automatically and unconditionally install faulthandlers as part of their normal operation. To prevent an issue simply insert a call to disable the faulthandler after the module has enabled it, using .. code-block:: python import faulthandler faulthandler.disable() For example, absl installs faulthandlers in ``app.run``, thus the first call to main routine would need to disable faulthandlers to avoid potential crashes. Unsupported Python versions --------------------------- Python 3.4 and earlier ~~~~~~~~~~~~~~~~~~~~~~ The oldest version of Python that we currently support is Python 3.5. Before Python 3.5 there were a number of structural difficulties in the object model and the buffering API. In principle, those features could be excised from JPype to extend support to older Python 3 series version, but that is unlikely to happen without a significant effort. Python 2 ~~~~~~~~ CPython 2 support was removed starting in 2020. Please do not report to us that Python 2 is not supported. Python 2 was a major drag on this project for years. Its object model is grossly outdated and thus providing for it greatly impeded progress. When the life support was finally pulled on that beast, I like many others breathed a great sigh of relief and gladly cut out the Python 2 code. Since that time JPype operating speed has improved anywhere from 300% to 10000% as we can now implement everything back in CPython rather than band-aiding it with interpreted Python code. PyPy ~~~~ The GC routine in PyPy 3 does not play well with Java. It runs when it thinks that Python is running out of resources. Thus a code that allocates a lot of Java memory and deletes the Python objects will still be holding the Java memory until Python is garbage collected. This means that out of memory failures can be issued during heavy operation. We have addressed linking the garbage collectors between CPython and Java, but PyPy would require a modified strategy. Further, when we moved to a completely Python 3 object model we unfortunately broke some of the features that are different between CPython and PyPy. The errors make absolutely no sense to me. So unless a PyPy developer generously volunteering time for this project, this one is unlikely to happen. Jython Python ~~~~~~~~~~~~~ If for some reason you wandered here to figure out how to use Java from Jython using JPype, you are clearly in the wrong place. On the other hand, if you happen to be a Jython developer who is looking for inspiration on how to support a more JPype like API that perhaps we can assist you. Jython aware Python modules often mistake JPype for Jython at least up until the point that differences in the API triggers an error. Unsupported Java virtual machines --------------------------------- The open JVM implementations *Cacao* and *JamVM* are known not to work with JPype. Unsupported Platforms --------------------- Some platforms are problematic for JPype due to interactions between the Python libraries and the JVM implementation. Cygwin ~~~~~~ Cygwin was usable with previous versions of JPype, but there were numerous issues for which there is was not good solution solution. Cygwin does not appear to pass environment variables to the JVM properly resulting in unusual behavior with certain windows calls. The path separator for Cygwin does not match that of the Java DLL, thus specification of class paths must account for this. Threading between the Cygwin libraries and the JVM was often unstable. .. _freezing: Freezing ======== JPype supports freezing and deployment with `PyInstaller `_. The hook is included with JPype installations and no extra configuration should be needed. jpype-1.3.0/examples/000077500000000000000000000000001405671516700144745ustar00rootroot00000000000000jpype-1.3.0/examples/jms/000077500000000000000000000000001405671516700152655ustar00rootroot00000000000000jpype-1.3.0/examples/jms/README.TXT000066400000000000000000000036761405671516700166370ustar00rootroot00000000000000This example of using JPype and JMS contributed by David Morgenthaler Here is the message that accompanied it when he posted it on comp.lang.python : ============================================================================= Your question intrigued me, so I gave it a try. And the anwer (at least for JMS Publish/Subscribe TextMessages) is YES. It includes: - Java classes for a publisher (src/messaging/JpypePublisher) and a subscriber (src/messaging/JpypeSubscriber). These Java classes, which do most of the dirty work of connecting to the JMS server, are used from python via jpype. - Java classes that test the publisher and subscriber (src/messaging/testJpepePublisher, src/messaging/testJpypeSubscriber) - A Java interface that is used by python for the JProxy - python scripts for publishing and subscribing - An build.xml for ant to build and run the Java classes The Java and python publishers and subscribers work in any reasonable combination (J pub/J sub, J pub/p sub, p pub/p sub, p pub/J sub, and even with multiple subscribers) Copy conveniently located folder. You'll find a build.xml for ant to build the Java. You'll have to edit (in the testers and in the python scripts) the naming and connection factory stuff for your situation. You'll also have to edit the python scripts to correctly locate your jvm and other classpath information. Once you're correctly configured, you can use ant to build and/or execute the Java (type "ant help"). And once the Java is built, you can try the python versions. I can't imagine that this approach wouldn't work for JMS Queues. And while I haven't tested it, I don't see anything preventing the use of other message types (BinaryMessage, ObjectMessage,...). BTW, I don't detect any noticable slowdown in the python versions from the Java versions (probably because of the strightforward conversion of python strings to Java Strings). ============================================================================= jpype-1.3.0/examples/jms/testJpypePublisher.py000066400000000000000000000022401405671516700215020ustar00rootroot00000000000000from jpype import * import time NUMMSGS = 10 def pyPublisher(javaNamingFactory="weblogic.jndi.WLInitialContextFactory", javaNamingProvider="t3://158.188.40.21:7001", connectionFactory="weblogic.jms.ConnectionFactory", topicName="defaultTopic"): return messaging.JpypePublisher(javaNamingFactory, javaNamingProvider, connectionFactory, topicName) # Startup Jpype and import the messaging java package startJVM("C:\\program files\\Java\\j2re1.4.2_02\\bin\\client\\jvm.dll", "-Djava.class.path=D:/jIRAD/JpypeJMS/src;D:/jIRAD/JpypeJMS/classes;C:/bea/weblogic81/server/lib/weblogic.jar") messaging = JPackage('messaging') # Get a publisher publisher = pyPublisher() # Timing test # The "Start" message signals the subscriber to start timing message receipts publisher.publish("Start") t0 = time.time() for i in range(NUMMSGS): publisher.publish("Hello World! %s" % i) print "MessageRate =", float(NUMMSGS) / (time.time() - t0) # The "Stop" message signals the subscriber to stop timing message receipts publisher.publish("Stop") # Close and quit publisher.close() shutdownJVM() jpype-1.3.0/examples/jms/testJpypeSubscriber.py000066400000000000000000000026141405671516700216550ustar00rootroot00000000000000from jpype import * import time def pySubscriber(proxy, javaNamingFactory="weblogic.jndi.WLInitialContextFactory", javaNamingProvider="t3://158.188.40.21:7001", connectionFactory="weblogic.jms.ConnectionFactory", topicName="defaultTopic"): return messaging.JpypeSubscriber(proxy, javaNamingFactory, javaNamingProvider, connectionFactory, topicName) # Startup Jpype and import the messaging java package startJVM("C:\\program files\\Java\\j2re1.4.2_02\\bin\\client\\jvm.dll", "-Djava.class.path=D:/jIRAD/JpypeJMS/src;D:/jIRAD/JpypeJMS/classes;C:/bea/weblogic81/server/lib/weblogic.jar") messaging = JPackage('messaging') # Setup the JProxy for the messaging.JpypeSubscriberCallback interface class pyCallback: startTime = 0 count = 0 def onMessage(self, text): print text if text == 'Start': pyCallback.startTime = time.time() pyCallback.count = 0 elif text == 'Stop': print "Message Rate =", float(pyCallback.count) / (time.time() - pyCallback.startTime) else: pyCallback.count += 1 c = pyCallback() proxy = JProxy(messaging.JpypeSubscriberCallback, inst=c) # Get a subscriber sub = pySubscriber(proxy) print "Listening..." # Prevent this thread from exiting time.sleep(1000) # exit shutdownJVM() jpype-1.3.0/examples/linux/000077500000000000000000000000001405671516700156335ustar00rootroot00000000000000jpype-1.3.0/examples/linux/README.TXT000066400000000000000000000016061405671516700171740ustar00rootroot00000000000000The 2 scripts in this directory are here to resolve a weakness in the linux implementation. Since the JVM is loaded dynamically, the LD_LIBRARY_PATH may not contain the proper directories. Unfortunately, dlopen() will ignore any changes made to the LD_LIBRARY_PATH in the current process. The jpype.sh is meant as an example for people redistributing apps using jpype. Instead of having users launch python script.py directly, have then launch script.sh. The companion findjvm.py can be delivered along your app, but is also present in the python distribution of jpype. Developpers are encouraged to make their lives simpler by adding the correct directories to their LD_LIBRARY_PATH directly. To learn more about the dlopen problem, you can look at : http://forum.java.sun.com/thread.jsp?forum=52&thread=303583&message=1210441 and http://www.nathanr.net/diary/index.php?year=2004&month=05 jpype-1.3.0/examples/linux/findjvm.py000066400000000000000000000015521405671516700176450ustar00rootroot00000000000000# ***************************************************************************** # Copyright 2004-2008 Steve Menard # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # ***************************************************************************** import jpype import os.path jvmlib = jpype.getDefaultJVMPath() print os.path.dirname(os.path.dirname(jvmlib)) jpype-1.3.0/examples/linux/jpype.sh000066400000000000000000000017201405671516700173160ustar00rootroot00000000000000#!/bin/sh #***************************************************************************** # Copyright 2004-2008 Steve Menard # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # #***************************************************************************** # # this script contributed by Dave Kuhlman, and modified By Steve menard # export JAVA_LIB_PATH=`python findjvm.py` export LD_LIBRARY_PATH=LD_LIBRARY_PATH:$JAVA_LIB_PATH:$JAVA_LIB_PATH/client python $*jpype-1.3.0/examples/rmi.py000066400000000000000000000022371405671516700156410ustar00rootroot00000000000000# ***************************************************************************** # Copyright 2004-2008 Steve Menard # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # ***************************************************************************** # the hava classes used are defined the the test harness. the class jpype.rmi.ServerImpl must be started before this script can be run. from jpype import * import os.path root = os.path.abspath(os.path.dirname(__file__)) startJVM(getDefaultJVMPath(), "-ea", "-Djava.class.path=%s/../test/classes" % root) p = java.rmi.Naming.lookup("rmi://localhost:2004/server") print p, p.__class__ p.callRemote() shutdownJVM() jpype-1.3.0/ivy.xml000066400000000000000000000021641405671516700142120ustar00rootroot00000000000000 jpype-1.3.0/jpype/000077500000000000000000000000001405671516700140055ustar00rootroot00000000000000jpype-1.3.0/jpype/__init__.py000066400000000000000000000047441405671516700161270ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import _jpype from ._jinit import * from ._jpackage import * from ._jproxy import * from ._core import * from ._gui import * from ._classpath import * from ._jclass import * from ._jobject import * # There is a bug in lgtm with __init__ imports. It will be fixed next month. from . import _jarray # lgtm [py/import-own-module] from . import _jexception # lgtm [py/import-own-module] from .types import * from ._jcustomizer import * from . import nio # lgtm [py/import-own-module] from . import types # lgtm [py/import-own-module] from ._jcustomizer import * # Import all the class customizers # Customizers are applied in the order that they are defined currently. from . import _jmethod # lgtm [py/import-own-module] from . import _jcollection # lgtm [py/import-own-module] from . import _jio # lgtm [py/import-own-module] from . import protocol # lgtm [py/import-own-module] from . import _jthread # lgtm [py/import-own-module] __all__ = ['java', 'javax'] __all__.extend(_jinit.__all__) __all__.extend(_core.__all__) __all__.extend(_classpath.__all__) __all__.extend(types.__all__) __all__.extend(_jproxy.__all__) __all__.extend(_jpackage.__all__) __all__.extend(_jclass.__all__) __all__.extend(_jcustomizer.__all__) __all__.extend(_gui.__all__) __version__ = "1.3.0" __version_info__ = __version__.split('.') # FIXME these should be deprecated. The old JPackage system is only for # python2 series and generates lots of deceptive classes. At some point # these two are going to have to go away. java = JPackage("java", strict=True) javax = JPackage("javax", strict=True) JMethod = _jpype._JMethod JField = _jpype._JField if hasattr(_jpype, 'bootstrap'): _jpype.bootstrap() _core.initializeResources() jpype-1.3.0/jpype/_classpath.py000066400000000000000000000060431405671516700165030ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import os as _os import _jpype __all__ = ['addClassPath', 'getClassPath'] _CLASSPATHS = [] _SEP = _os.path.pathsep def addClassPath(path1): """ Add a path to the Java class path Classpath items can be a java, a directory, or a glob pattern. Relative paths are relative to the caller location. Arguments: path(str): """ # We are deferring these imports until here as we only need them # if this function is used. from pathlib import Path import inspect global _CLASSPATHS # Convert to an absolute path. Note that # relative paths will be resolve based on the location # of the caller rather than the JPype directory. path1 = Path(path1) if not path1.is_absolute(): path2 = Path(inspect.stack(1)[1].filename).parent.resolve() path1 = path2.joinpath(path1) # If the JVM is already started then we will have to load the paths # immediately into the DynamicClassLoader if _jpype.isStarted(): Paths = _jpype.JClass('java.nio.file.Paths') JContext = _jpype.JClass('org.jpype.JPypeContext') classLoader = JContext.getInstance().getClassLoader() if path1.name == "*": paths = list(path1.parent.glob("*.jar")) if len(paths) == 0: return for path in paths: classLoader.addFile(Paths.get(str(path))) else: classLoader.addFile(Paths.get(str(path1))) _CLASSPATHS.append(path1) def getClassPath(env=True): """ Get the full Java class path. Includes user added paths and the environment CLASSPATH. Arguments: env(Optional, bool): If true then environment is included. (default True) """ from pathlib import Path global _CLASSPATHS global _SEP # Merge the evironment path classPath = list(_CLASSPATHS) envPath = _os.environ.get("CLASSPATH") if env and envPath: classPath.extend([Path(i) for i in envPath.split(_SEP)]) out = [] for path in classPath: if path == '': continue if path.name == "*": paths = list(path.parent.glob("*.jar")) if len(paths) == 0: continue out.extend(paths) else: out.append(path) return _SEP.join([str(i) for i in out]) jpype-1.3.0/jpype/_core.py000066400000000000000000000406561405671516700154610ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import sys import atexit import _jpype from . import types as _jtypes from . import _classpath from . import _jcustomizer from . import _jinit from . import _pykeywords from ._jvmfinder import * # This import is required to bootstrap importlib, _jpype uses importlib.util # but on some systems it may not load properly from C. To make sure it gets # loaded properly we are going to force the issue even through we don't # use it in this module. (Do not remove) from importlib import util as _util __all__ = [ 'isJVMStarted', 'startJVM', 'shutdownJVM', 'getDefaultJVMPath', 'getJVMVersion', 'isThreadAttachedToJVM', 'attachThreadToJVM', 'detachThreadFromJVM', 'synchronized', 'JVMNotFoundException', 'JVMNotSupportedException', 'JVMNotRunning' ] class JVMNotRunning(RuntimeError): pass def versionTest(): if sys.version_info < (3,): raise ImportError("Python 2 is not supported") versionTest() # Activate jedi tab completion try: import jedi as _jedi _jedi.evaluate.compiled.access.ALLOWED_DESCRIPTOR_ACCESS += \ (_jpype._JMethod, _jpype._JField) except Exception: pass # See http://scottlobdell.me/2015/04/decorators-arguments-python/ def deprecated(*args): """ Marks a function a deprecated when used as decorator. Be sure to start python with -Wd to see warnings. """ def func2(*args, **kwargs): import warnings if not func2._warned: warnings.warn(func2._warning % (func2._real.__module__, func2._real.__name__), category=DeprecationWarning, stacklevel=2) func2._warned = True return func2._real(*args, **kwargs) if isinstance(args[0], str): def decorate(func): func2.__name__ = func.__name__ func2.__doc__ = func.__doc__ func2._warned = False func2._real = func func2._warning = "%s.%s is deprecated, use {0} instead".format( args[0]) return func2 return decorate else: func = args[0] func2.__name__ = func.__name__ func2.__doc__ = func.__doc__ func2._warned = False func2._real = func func2._warning = "%s.%s is deprecated" return func2 def isJVMStarted(): """ True if the JVM is currently running.""" # TODO This method is horribly named. It should be named isJVMRunning as # isJVMStarted would seem to imply that the JVM was started at some # point without regard to whether it has been shutdown. # return _jpype.isStarted() def _hasClassPath(args): for i in args: if i.startswith('-Djava.class.path'): return True return False def _handleClassPath(clsList): out = [] for s in clsList: if not isinstance(s, str): raise TypeError("Classpath elements must be strings") if s.endswith('*'): import glob out.extend(glob.glob(s + '.jar')) else: out.append(s) return _classpath._SEP.join(out) _JVM_started = False def interactive(): return bool(getattr(sys, 'ps1', sys.flags.interactive)) def startJVM(*args, **kwargs): """ Starts a Java Virtual Machine. Without options it will start the JVM with the default classpath and jvmpath. The default classpath is determined by ``jpype.getClassPath()``. The default jvmpath is determined by ``jpype.getDefaultJVMPath()``. Parameters: *args (Optional, str[]): Arguments to give to the JVM. The first argument may be the path the JVM. Keyword Arguments: jvmpath (str): Path to the jvm library file, Typically one of (``libjvm.so``, ``jvm.dll``, ...) Using None will apply the default jvmpath. classpath (str,[str]): Set the classpath for the JVM. This will override any classpath supplied in the arguments list. A value of None will give no classpath to JVM. ignoreUnrecognized (bool): Option to ignore invalid JVM arguments. Default is False. convertStrings (bool): Option to force Java strings to cast to Python strings. This option is to support legacy code for which conversion of Python strings was the default. This will globally change the behavior of all calls using strings, and a value of True is NOT recommended for newly developed code. interrupt (bool): Option to install ^C signal handlers. If True then ^C will stop the process, else ^C will transfer control to Python rather than halting. If not specified will be False if Python is started as an interactive shell. Raises: OSError: if the JVM cannot be started or is already running. TypeError: if an invalid keyword argument is supplied or a keyword argument conflicts with the arguments. """ if _jpype.isStarted(): raise OSError('JVM is already started') global _JVM_started if _JVM_started: raise OSError('JVM cannot be restarted') args = list(args) # JVM path jvmpath = None if args: # jvm is the first argument the first argument is a path or None if not args[0] or not args[0].startswith('-'): jvmpath = args.pop(0) if 'jvmpath' in kwargs: if jvmpath: raise TypeError('jvmpath specified twice') jvmpath = kwargs.pop('jvmpath') if not jvmpath: jvmpath = getDefaultJVMPath() # Classpath handling if _hasClassPath(args): # Old style, specified in the arguments if 'classpath' in kwargs: # Cannot apply both styles, conflict raise TypeError('classpath specified twice') classpath = None elif 'classpath' in kwargs: # New style, as a keywork classpath = kwargs.pop('classpath') else: # Not speficied at all, use the default classpath classpath = _classpath.getClassPath() # Handle strings and list of strings. if classpath: if isinstance(classpath, str): args.append('-Djava.class.path=%s' % _handleClassPath([classpath])) elif hasattr(classpath, '__iter__'): args.append('-Djava.class.path=%s' % _handleClassPath(classpath)) else: raise TypeError("Unknown class path element") ignoreUnrecognized = kwargs.pop('ignoreUnrecognized', False) convertStrings = kwargs.pop('convertStrings', False) interrupt = kwargs.pop('interrupt', not interactive()) if kwargs: raise TypeError("startJVM() got an unexpected keyword argument '%s'" % (','.join([str(i) for i in kwargs]))) try: _jpype.startup(jvmpath, tuple(args), ignoreUnrecognized, convertStrings, interrupt) initializeResources() except RuntimeError as ex: source = str(ex) if "UnsupportedClassVersion" in source: import re match = re.search(r"([0-9]+)\.[0-9]+", source) if match: version = int(match.group(1)) - 44 raise RuntimeError("%s is older than required Java version %d" % ( jvmpath, version)) from ex raise def initializeResources(): global _JVM_started _jpype._java_lang_Class = None _jpype._java_lang_Object = _jpype.JClass("java.lang.Object") _jpype._java_lang_Throwable = _jpype.JClass("java.lang.Throwable") _jpype._java_lang_Exception = _jpype.JClass("java.lang.Exception") _jpype._java_lang_Class = _jpype.JClass("java.lang.Class") _jpype._java_lang_String = _jpype.JClass("java.lang.String") _jpype._java_lang_RuntimeException = _jpype.JClass( "java.lang.RuntimeException") # Preload needed classes _jpype._java_lang_Boolean = _jpype.JClass("java.lang.Boolean") _jpype._java_lang_Byte = _jpype.JClass("java.lang.Byte") _jpype._java_lang_Character = _jpype.JClass("java.lang.Character") _jpype._java_lang_Short = _jpype.JClass("java.lang.Short") _jpype._java_lang_Integer = _jpype.JClass("java.lang.Integer") _jpype._java_lang_Long = _jpype.JClass("java.lang.Long") _jpype._java_lang_Float = _jpype.JClass("java.lang.Float") _jpype._java_lang_Double = _jpype.JClass("java.lang.Double") # Bind types _jpype.JString.class_ = _jpype._java_lang_String _jpype.JObject.class_ = _jpype._java_lang_Object _jtypes.JBoolean.class_ = _jpype._java_lang_Boolean.TYPE _jtypes.JByte.class_ = _jpype._java_lang_Byte.TYPE _jtypes.JChar.class_ = _jpype._java_lang_Character.TYPE _jtypes.JShort.class_ = _jpype._java_lang_Short.TYPE _jtypes.JInt.class_ = _jpype._java_lang_Integer.TYPE _jtypes.JLong.class_ = _jpype._java_lang_Long.TYPE _jtypes.JFloat.class_ = _jpype._java_lang_Float.TYPE _jtypes.JDouble.class_ = _jpype._java_lang_Double.TYPE _jtypes.JBoolean._hints = _jcustomizer.getClassHints("boolean") _jtypes.JByte._hints = _jcustomizer.getClassHints("byte") _jtypes.JChar._hints = _jcustomizer.getClassHints("char") _jtypes.JShort._hints = _jcustomizer.getClassHints("short") _jtypes.JInt._hints = _jcustomizer.getClassHints("int") _jtypes.JLong._hints = _jcustomizer.getClassHints("long") _jtypes.JFloat._hints = _jcustomizer.getClassHints("float") _jtypes.JDouble._hints = _jcustomizer.getClassHints("double") # Table for automatic conversion to objects "JObject(value, type)" _jpype._object_classes = {} # These need to be deprecated so that we can support casting Python objects _jpype._object_classes[bool] = _jpype._java_lang_Boolean _jpype._object_classes[int] = _jpype._java_lang_Long _jpype._object_classes[float] = _jpype._java_lang_Double _jpype._object_classes[str] = _jpype._java_lang_String _jpype._object_classes[type] = _jpype._java_lang_Class _jpype._object_classes[object] = _jpype._java_lang_Object _jpype._object_classes[_jpype._JClass] = _jpype._java_lang_Class _jpype._object_classes[_jtypes.JBoolean] = _jpype._java_lang_Boolean _jpype._object_classes[_jtypes.JByte] = _jpype._java_lang_Byte _jpype._object_classes[_jtypes.JChar] = _jpype._java_lang_Character _jpype._object_classes[_jtypes.JShort] = _jpype._java_lang_Short _jpype._object_classes[_jtypes.JInt] = _jpype._java_lang_Integer _jpype._object_classes[_jtypes.JLong] = _jpype._java_lang_Long _jpype._object_classes[_jtypes.JFloat] = _jpype._java_lang_Float _jpype._object_classes[_jtypes.JDouble] = _jpype._java_lang_Double _jpype._object_classes[type(None)] = _jpype._java_lang_Object _jpype._object_classes[_jpype.JString] = _jpype._java_lang_String # Set up table of automatic conversions of Python primitives # this table supports "JArray(type)" _jpype._type_classes = {} _jpype._type_classes[bool] = _jtypes.JBoolean _jpype._type_classes[int] = _jtypes.JLong _jpype._type_classes[float] = _jtypes.JDouble _jpype._type_classes[str] = _jpype._java_lang_String _jpype._type_classes[type] = _jpype._java_lang_Class _jpype._type_classes[object] = _jpype._java_lang_Object _jpype._type_classes[_jpype.JString] = _jpype._java_lang_String _jpype._type_classes[_jpype.JObject] = _jpype._java_lang_Object _jinit.runJVMInitializers() _jpype.JClass('org.jpype.JPypeKeywords').setKeywords( list(_pykeywords._KEYWORDS)) _jpype.JPypeContext = _jpype.JClass('org.jpype.JPypeContext').getInstance() _jpype.JPypeClassLoader = _jpype.JPypeContext.getClassLoader() # Everything successed so started is now true. _JVM_started = True def shutdownJVM(): """ Shuts down the JVM. This method shuts down the JVM and disables access to existing Java objects. Due to limitations in the JPype, it is not possible to restart the JVM after being terminated. """ import threading import jpype.config if threading.current_thread() is not threading.main_thread(): raise RuntimeError("Shutdown must be called from main thread") if _jpype.isStarted(): _jpype.JPypeContext.freeResources = jpype.config.free_resources _jpype.shutdown(jpype.config.destroy_jvm, False) # In order to shutdown cleanly we need the reference queue stopped # otherwise, we can experience a crash if a Java thread is waiting # for the GIL. def _JTerminate(): try: import jpype.config # We are exiting anyway so no need to free resources if _jpype.isStarted(): _jpype.JPypeContext.freeResources = False if jpype.config.onexit: _jpype.shutdown(jpype.config.destroy_jvm, False) except RuntimeError: pass atexit.register(_JTerminate) @deprecated("java.lang.Thread.isAttached") def isThreadAttachedToJVM(): """ Checks if a thread is attached to the JVM. Python automatically attaches threads when a Java method is called. This creates a resource in Java for the Python thread. This method can be used to check if a Python thread is currently attached so that it can be disconnected prior to thread termination to prevent leaks. Returns: True if the thread is attached to the JVM, False if the thread is not attached or the JVM is not running. """ return _jpype.isThreadAttachedToJVM() @deprecated("java.lang.Thread.attach") def attachThreadToJVM(): """ Attaches a thread to the JVM. The function manually connects a thread to the JVM to allow access to Java objects and methods. JPype automatically attaches when a Java resource is used, so a call to this is usually not needed. Raises: RuntimeError: If the JVM is not running. """ _jpype.attachThreadToJVM() @deprecated("java.lang.Thread.detach") def detachThreadFromJVM(): """ Detaches a thread from the JVM. This function detaches the thread and frees the associated resource in the JVM. For codes making heavy use of threading this should be used to prevent resource leaks. The thread can be reattached, so there is no harm in detaching early or more than once. This method cannot fail and there is no harm in calling it when the JVM is not running. """ _jpype.detachThreadFromJVM() def synchronized(obj): """ Creates a resource lock for a Java object. Produces a monitor object. During the lifespan of the monitor Java will not be able to acquire a thread lock on the object. This will prevent multiple threads from modifying a shared resource. This should always be used as part of a Python ``with`` startment. Arguments: obj: A valid Java object shared by multiple threads. Example: .. code-block:: python with synchronized(obj): # modify obj values # lock is freed when with block ends """ return _jpype._JMonitor(obj) def getJVMVersion(): """ Get the JVM version if the JVM is started. This function can be used to determine the version of the JVM. It is useful to help determine why a Jar has failed to load. Returns: A typle with the (major, minor, revison) of the JVM if running. """ if not _jpype.isStarted(): return (0, 0, 0) import re runtime = _jpype.JClass('java.lang.Runtime') version = runtime.class_.getPackage().getImplementationVersion() # Java 9+ has a version method if not version: version = runtime.version() version = (re.match("([0-9.]+)", str(version)).group(1)) return tuple([int(i) for i in version.split('.')]) @_jcustomizer.JImplementationFor("java.lang.Runtime") class _JRuntime(object): # We need to redirect hooks so that we control the order def addShutdownHook(self, thread): return _jpype.JClass("org.jpype.JPypeContext").getInstance().addShutdownHook(thread) def removeShutdownHook(self, thread): return _jpype.JClass("org.jpype.JPypeContext").getInstance().removeShutdownHook(thread) _jpype.JVMNotRunning = JVMNotRunning jpype-1.3.0/jpype/_core.pyi000066400000000000000000000000321405671516700156120ustar00rootroot00000000000000class _JRuntime: pass jpype-1.3.0/jpype/_gui.py000066400000000000000000000026241405671516700153060ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import sys as _sys from . import _jproxy from . import _jclass __all__ = ['setupGuiEnvironment', 'shutdownGuiEnvironment'] # FIXME this is not documented # FIXME this is darwin specific def setupGuiEnvironment(cb): if _sys.platform == 'darwin': from PyObjCTools import AppHelper m = {'run': cb} proxy = _jproxy.JProxy('java.lang.Runnable', m) cbthread = _jclass.JClass("java.lang.Thread")(proxy) cbthread.start() AppHelper.runConsoleEventLoop() else: cb() def shutdownGuiEnvironment(): if _sys.platform == 'darwin': from PyObjCTools import AppHelper AppHelper.stopEventLoop() jpype-1.3.0/jpype/_jarray.py000066400000000000000000000140571405671516700160150ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import _jpype from . import _jcustomizer __all__ = ['JArray'] class JArray(_jpype._JObject, internal=True): """ Creates a Java array class for a Java type of a given dimension. This serves as a base type and factory for all Java array classes. The resulting Java array class can be used to construct a new array with a given size or specified members. JPype arrays support Python operators for iterating, length, equals, not equals, subscripting, and slicing. They also support Java object methods, clone, and length property. Java arrays may not be resized, and as such elements cannot be added nor deleted. Currently, applying the slice operator produces a new Python sequence. Example: .. code-block:: python # Define a new array class for ``int[]`` IntArrayCls = JArray(JInt) # Create an array holding 10 elements # equivalent to Java ``int[] x=new int[10]`` x = IntArrayCls(10) # Create a length 3 array initialized with [1,2,3] # equivalent to Java ``int[] x = new int[]{1,2,3};`` x = IntArrayCls([1,2,3]) # Operate on an array print(len(x)) print(x[0]) print(x[:-2]) x[1:]=(5,6) if isinstance(x, JArray): print("object is a java array") if issubclass(IntArrayCls, JArray): print("class is a java array type.") Args: javaClass (str,type): Is the type of element to hold in the array. ndims (Optional,int): the number of dimensions of the array (default=1) Returns: A new Python class that representing a Java array class. Raises: TypeError: if the component class is invalid or could not be found. Note: javaClass can be specified in three ways: - as a string with the name of a java class. - as a Java primitive type such as ``jpype.JInt``. - as a Java class type such as ``java.lang.String``. """ def __new__(cls, tp, dims=1): if cls != JArray: raise TypeError("Arrays factory can't be used as type") jc = _toJavaClass(tp) return _jpype._newArrayType(jc, dims) @classmethod def of(cls, array, dtype=None): return _jpype.arrayFromBuffer(array, dtype) class _JArrayProto(object): def __str__(self): return str(list(self)) def __iter__(self): return _JavaArrayIter(self) def __reversed__(self): for elem in self[::-1]: yield elem def clone(self): """ Clone the Java array. Create a "shallow" copy of a Java array. For a single dimensional array of primitives, the cloned array is complete independent copy of the original. For objects or multidimensional arrays, the new array is a copy which points to the same members as the original. To obtain a deep copy of a Java array, use Java serialize and deserialize operations to duplicate the entire array and contents. In order to deep copy, the objects must be Serializable. Returns: A shallow copy of the array. """ return _jpype.JClass("java.util.Arrays").copyOf(self, len(self)) def _toJavaClass(tp): """(internal) Converts a class type in python into a internal java class. Used mainly to support JArray. The type argument will operate on: - (str) lookup by class name or fail if not found. - (JClass) just returns the java type. - (type) uses a lookup table to find the class. """ # if it a string than we lookup the class by name. if isinstance(tp, str): return _jpype._java_lang_Class.forName(tp) # if is a java.lang.Class instance, then no coversion required if isinstance(tp, _jpype._JClass): return tp # Okay then it must be a type try: return _jpype._type_classes[tp].class_ except KeyError: pass # See if it a class type try: return tp.class_ except AttributeError: pass raise TypeError("Unable to find class for '%s'" % tp.__name__) # FIXME are these not sequences? They act like sequences but are they # connected to collections.abc.Sequence # has: __len__, __iter__, __getitem__ # missing: __contains__ (required for in) # Cannot be Mutable because java arrays are fixed in length class _JavaArrayIter(object): def __init__(self, a): self._array = a self._ndx = -1 def __iter__(self): return self def __next__(self): self._ndx += 1 if self._ndx >= len(self._array): raise StopIteration return self._array[self._ndx] next = __next__ # ********************************************************** # Char array customizer @_jcustomizer.JImplementationFor("byte[]") @_jcustomizer.JImplementationFor("char[]") class _JCharArray(object): def __str__(self): return str(_jpype.JString(self)) def __eq__(self, other): if isinstance(other, str): return str(self) == other try: return self.equals(self.__class__(other)) except TypeError: return False __hash__ = _jpype._JObject.__hash__ # Install module hooks _jcustomizer._applyCustomizerPost(_jpype._JArray, _JArrayProto) _jpype.JArray = JArray jpype-1.3.0/jpype/_jclass.py000066400000000000000000000176651405671516700160140ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import _jpype from ._pykeywords import pysafe from . import _jcustomizer __all__ = ['JClass', 'JInterface', 'JOverride'] def JOverride(*args, **kwargs): """Annotation to denote a method as overriding a Java method. This annotation applies to customizers, proxies, and extensions to Java classes. Apply it to methods to mark them as implementing or overriding Java methods. Keyword arguments are passed to the corresponding implementation factory. Args: sticky=bool: Applies a customizer method to all derived classes. """ # Check if called bare if len(args) == 1 and callable(args[0]): object.__setattr__(args[0], "__joverride__", {}) return args[0] # Otherwise apply arguments as needed def modifier(method): object.__setattr__(method, "__joverride__", kwargs) return method return modifier class JClassMeta(type): def __instancecheck__(self, other): return type(other) == _jpype._JClass class JClass(_jpype._JClass, metaclass=JClassMeta): """Meta class for all Java class instances. When called as an object, JClass will contruct a new Java class wrapper. All Python wrappers for Java classes derive from this type. To test if a Python class is a Java wrapper use ``isinstance(obj, jpype.JClass)``. Args: className (str): name of a Java type. Keyword Args: loader (java.lang.ClassLoader): specifies a class loader to use when creating a class. initialize (bool): If true the class will be loaded and initialized. Otherwise, static members will be uninitialized. Returns: JavaClass: a new wrapper for a Java class Raises: TypeError: if the component class is invalid or could not be found. """ def __new__(cls, jc, loader=None, initialize=True): if loader and isinstance(jc, str): jc = _jpype._java_lang_Class.forName(jc, initialize, loader) # Handle generics if isinstance(jc, str) and jc.endswith(">"): i = jc.find("<") params = jc[i + 1:-1] ret = _jpype._getClass(jc[:i]) acceptParams = len(ret.class_.getTypeParameters()) if acceptParams == 0: raise TypeError( "Java class '%s' does not take parameters" % (ret.__name__)) if len(params) > 0: params = params.split(',') if len(params) > 0 and len(params) != len(ret.class_.getTypeParameters()): raise TypeError( "Java generic class '%s' length mismatch" % (ret.__name__)) return ret # Pass to class factory to create the type return _jpype._getClass(jc) class JInterface(_jpype._JObject, internal=True): """A meta class for all Java Interfaces. ``JInterface`` is serves as the base class for any Java class that is a pure interface without implementation. It is not possible to create a instance of a Java interface. Example: .. code-block:: python if isinstance(java.util.function.Function, jpype.JInterface): print("is interface") """ pass def _jclassPre(name, bases, members): # Correct keyword conflicts with Python m = list(members.items()) for k, v in m: k2 = pysafe(k) if k2 != k: del members[k] members[k2] = v # Apply customizers hints = _jcustomizer.getClassHints(name) hints.applyCustomizers(name, bases, members) return (name, tuple(bases), members) def _jclassPost(res, *args): # Post customizers hints = _jcustomizer.getClassHints(res.__name__) res._hints = hints hints.applyInitializer(res) # Attach public inner classes we find # Due to bootstrapping, we must wait until java.lang.Class is defined # before we can access the class structures. if _jpype._java_lang_Class: for cls in res.class_.getDeclaredClasses(): if cls.getModifiers() & 1 == 0: continue wrapper = _jpype.JClass(cls) res._customize(str(cls.getSimpleName()), wrapper) def _jclassDoc(cls): """Generator for JClass.__doc__ property Parameters: cls (JClass): class to document. Returns: The doc string for the class. """ out = [] if not hasattr(cls, "__javadoc__"): jde = JClass("org.jpype.javadoc.JavadocExtractor")() jd = jde.getDocumentation(cls) if jd is not None: setattr(cls, "__javadoc__", jd) if jd.description is not None: out.append(str(jd.description)) if jd.ctors is not None: out.append(str(jd.ctors)) return "".join(out) setattr(cls, "__javadoc__", None) from textwrap import TextWrapper jclass = cls.class_ out.append("Java class '%s'" % (jclass.getName())) out.append("") sup = jclass.getSuperclass() if sup: out.append(" Extends:") out.append(" %s" % sup.getName()) out.append("") intfs = jclass.getInterfaces() if intfs: out.append(" Interfaces:") words = ", ".join([str(i.getCanonicalName()) for i in intfs]) wrapper = TextWrapper(initial_indent=' ' * 8, subsequent_indent=' ' * 8) out.extend(wrapper.wrap(words)) out.append("") ctors = jclass.getDeclaredConstructors() if ctors: exceptions = [] name = jclass.getSimpleName() ctordecl = [] for ctor in ctors: modifiers = ctor.getModifiers() if not modifiers & 1: continue params = ", ".join([str(i.getCanonicalName()) for i in ctor.getParameterTypes()]) ctordecl.append(" * %s(%s)" % (name, params)) exceptions.extend(ctor.getExceptionTypes()) if ctordecl: out.append(" Constructors:") out.extend(ctordecl) out.append("") if exceptions: out.append(" Raises:") for exc in set(exceptions): out.append(" %s: from java" % exc.getCanonicalName()) out.append("") fields = jclass.getDeclaredFields() if fields: fielddesc = [] for field in fields: modifiers = field.getModifiers() if not modifiers & 1: continue fieldInfo = [] if modifiers & 16: fieldInfo.append("final") if modifiers & 8: fieldInfo.append("static") if field.isEnumConstant(): fieldInfo.append("enum constant") else: fieldInfo.append("field") fielddesc.append(" %s (%s): %s" % (field.getName(), field.getType().getName(), " ".join(fieldInfo))) if fielddesc: out.append(" Attributes:") out.extend(fielddesc) out.append("") return "\n".join(out) # Install module hooks _jpype.JClass = JClass _jpype.JInterface = JInterface _jpype._jclassDoc = _jclassDoc _jpype._jclassPre = _jclassPre _jpype._jclassPost = _jclassPost jpype-1.3.0/jpype/_jcollection.py000066400000000000000000000162231405671516700170270ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import _jpype from . import _jclass from . import types as _jtypes from . import _jcustomizer from collections.abc import Mapping, Sequence, MutableSequence JOverride = _jclass.JOverride @_jcustomizer.JImplementationFor("java.lang.Iterable") class _JIterable(object): """ Customizer for ``java.util.Iterable`` This customizer adds the Python iterator syntax to classes that implement Java Iterable. """ def __iter__(self): return self.iterator() @_jcustomizer.JImplementationFor("java.util.Collection") class _JCollection(object): """ Customizer for ``java.util.Collection`` This customizer adds the Python functions ``len()`` and ``del`` to Java Collions to allow for Python syntax. """ def __len__(self): return self.size() def __delitem__(self, i): raise TypeError( "'%s' does not support item deletion, use remove() method" % type(self).__name__) def __contains__(self, i): try: return self.contains(i) except TypeError: return False def _sliceAdjust(slc, size): start = slc.start stop = slc.stop if slc.step and (slc.step > 1 or slc.step < 0): raise TypeError("Stride not supported") if start is None: start = 0 if stop is None: stop = size if start < 0: start += size if stop < 0: stop += size return slice(start, stop) @_jcustomizer.JImplementationFor('java.util.List') class _JList(object): """ Customizer for ``java.util.List`` This customizer adds the Python list operator to function on classes that implement the Java List interface. """ def __jclass_init__(self): Sequence.register(self) MutableSequence.register(self) def __getitem__(self, ndx): if isinstance(ndx, slice): ndx = _sliceAdjust(ndx, self.size()) return self.subList(ndx.start, ndx.stop) else: if ndx < 0: ndx += self.size() return self.get(ndx) def __setitem__(self, ndx, v): if isinstance(ndx, slice): ndx = _sliceAdjust(ndx, self.size()) self[ndx.start:ndx.stop].clear() self.addAll(ndx.start, v) else: if ndx < 0: ndx += self.size() self.set(ndx, v) def __delitem__(self, ndx): if isinstance(ndx, slice): ndx = _sliceAdjust(ndx, self.size()) self[ndx.start:ndx.stop].clear() elif hasattr(ndx, '__index__'): if ndx < 0: ndx += self.size() return self.remove_(_jtypes.JInt(ndx)) else: raise TypeError("Incorrect arguments to del") def __reversed__(self): iterator = self.listIterator(self.size()) while iterator.hasPrevious(): yield iterator.previous() def index(self, obj): try: return self.indexOf(obj) except TypeError: raise ValueError("%s is not in list" % repr(obj)) def count(self, obj): try: jo = _jpype.JObject(obj) c = 0 for i in self: if i.equals(jo): c += 1 return c except TypeError: return 0 def insert(self, idx, obj): if idx < 0: idx += self.size() return self.add(idx, obj) def append(self, obj): return self.add(obj) def reverse(self): _jpype.JClass("java.util.Collections").reverse(self) def extend(self, lst): self.addAll(lst) def pop(self, idx=-1): if idx < 0: idx += self.size() return self.remove_(_jtypes.JInt(idx)) def __iadd__(self, obj): self.add(obj) return self def __add__(self, obj): new = self.clone() new.extend(obj) return new @JOverride(sticky=True, rename='remove_') def remove(self, obj): try: rc = self.remove_(_jpype.JObject(obj, _jpype.JObject)) if rc is True: return except TypeError: pass raise ValueError("item not in list") @_jcustomizer.JImplementationFor('java.util.Map') class _JMap(object): """ Customizer for ``java.util.Map`` This customizer adds the Python list and len operators to classes that implement the Java Map interface. """ def __jclass_init__(self): Mapping.register(self) def __len__(self): return self.size() def __iter__(self): return self.keySet().iterator() def __delitem__(self, i): return self.remove(i) def __getitem__(self, ndx): try: item = self.get(ndx) if item is not None or self.containsKey(ndx): return item except TypeError: pass raise KeyError('%s' % ndx) def __setitem__(self, ndx, v): self.put(ndx, v) def items(self): return self.entrySet() def keys(self): return list(self.keySet()) def __contains__(self, item): try: return self.containsKey(item) except TypeError: return False @_jcustomizer.JImplementationFor('java.util.Set') class _JSet(object): def __delitem__(self, i): return self.remove(i) @_jcustomizer.JImplementationFor("java.util.Map.Entry") class _JMapEntry(object): def __len__(self): return 2 def __getitem__(self, x): if x == 0: return self.getKey() if x == 1: return self.getValue() raise IndexError("Pairs are always length 2") @_jcustomizer.JImplementationFor('java.util.Iterator') class _JIterator(object): """ Customizer for ``java.util.Iterator`` This customizer adds the Python iterator concept to classes that implement the Java Iterator interface. """ def __next__(self): if self.hasNext(): return self.next() raise StopIteration def __iter__(self): return self @_jcustomizer.JImplementationFor('java.util.Enumeration') class _JEnumeration(object): """ Customizer for ``java.util.Enumerator`` This customizer adds the Python iterator concept to classes that implement the Java Enumerator interface. """ def __next__(self): if self.hasMoreElements(): return self.nextElement() raise StopIteration def __iter__(self): return self next = __next__ jpype-1.3.0/jpype/_jcollection.pyi000066400000000000000000000037511405671516700172020ustar00rootroot00000000000000from typing import Iterable, Collection, List, Set, Mapping, Tuple, TypeVar, Iterator, Generator, Union, overload E = TypeVar('E') K = TypeVar('K') V = TypeVar('V') class _JIterable(Iterable[E]): def __iter__(self) -> Iterator[E]: ... class _JCollection(Collection[E]): def __len__(self) -> int: ... def __delitem__(self, i: E) -> None: ... def __contains__(self, i: E) -> bool: ... class _JList(List[E]): @overload def __getitem__(self, ndx: int) -> E: ... @overload def __getitem__(self, ndx: slice) -> E: ... def __setitem__(self, ndx: int, v: E) -> None: ... def __delitem__(self, ndx: int) -> E: ... def __reversed__(self) -> Generator[E, None, None]: ... def index(self, obj: E) -> int: ... def count(self, obj: E) -> int: ... def insert(self, idx: int, obj: E) -> '_JList'[E]: ... def append(self, obj: E) -> '_JList'[E]: ... def reverse(self) -> None: ... def extend(self, lst: Iterable[E]) -> None: ... def pop(self, idx: int = ...) -> E: ... def __iadd__(self, obj: List[E]) -> '_JList'[E]: ... def __add__(self, obj: List[E]) -> '_JList'[E]: ... def remove(self, obj: E) -> None: ... class _JMap(Mapping[K, V]): def __len__(self) -> int: ... def __iter__(self) -> Iterator[K]: ... def __delitem__(self, i: K) -> V: ... def __getitem__(self, ndx: K) -> V: ... def __setitem__(self, ndx: K, v: V) -> None: ... def items(self) -> Set['_JMapEntry'[K, V]]: ... def keys(self) -> Set[K]: ... def __contains__(self, item: V) -> bool: ... class _JSet(Set[E]): def __delitem__(self, i: E): ... class _JMapEntry(Tuple[K, V]): def __len__(self) -> int: ... def __getitem__(self, x: int) -> Union[K, V]: ... class _JIterator(Iterator[E]): def __next__(self) -> E: ... def __iter__(self) -> Iterator[E]: ... class _JEnumeration(Iterator[E]): def __next__(self) -> E: ... def __iter__(self) -> Iterator[E]: ... def next(self) -> E: ... jpype-1.3.0/jpype/_jcustomizer.py000066400000000000000000000241251405671516700171000ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import _jpype __all__ = ['JImplementationFor', 'JConversion'] # Member types that are copied from the prototype _jcopymembers = (str, property, staticmethod, classmethod) def JConversion(cls, exact=None, instanceof=None, attribute=None, excludes=None): """ Decorator to define a method as a converted a Java type. Whenever a method resolution is called the JPype internal rules are applied, but this may be insufficient. If only a single method requires modification then a class customizer can be applied. But if many interfaces require the same conversion than a user conversion may be a better option. To add a user conversion define a method which take the requested Java type as the first argument, the target object to be converted as the second argument and returns a Java object or Java proxy that matches the required type. If the type is not a Java type then a TypeError will be raised. This method is only evaluated after the match has been determine prior to calling. Care should be used when defining a user conversion. If example if one has an interface that requires a specific class and you want it to take a Python string, then a user conversion can do that. On the other hand, if you define a generic converter of any Python object to a Java string, then every interface will attempt to call the conversion method whenever a Java string is being matched, which can cause many methods to potentially become ambiguous. Conversion are not inherited. If the same converter needs to apply to multiple types, then multiple decorators can be applied to the same method. Args: cls(str, JClass): The class that will be produced by this conversion. exact(type): This conversion applies only to objects that have a type exactly equal to the argument. instanceof(type or protocol): This conversion applies to any object that passes isinstance(obj, type). attribute(str): This conversion applies to any object that has passes hasattr(obj, arg). (deprecated) excludes(type): Prevents a conversion for a specified type. Can be used to prevent a specific type from being converted. For example, to prevent maps or strings from passing a check for Sequence. Exclusions are applied before all other user specificied conversions. """ hints = getClassHints(cls) if excludes is not None: hints._excludeConversion(excludes) def customizer(func=None): if exact is not None: hints._addTypeConversion(exact, func, True) if instanceof is not None: hints._addTypeConversion(instanceof, func, False) if attribute is not None: hints._addAttributeConversion(attribute, func) return func return customizer def JImplementationFor(clsname, base=False): """ Decorator to define an implementation for a class. Applies to a class which will serve as a prototype as for the Java class wrapper. If it is registered as a base class, then the class must derive from JObject. Otherwise, the methods are copied from the prototype to the Java class wrapper. The method ``__jclass_init__(cls)`` will be called with the constructed class as the argument. This call is used to set methods for all classes that derive from the specified class. Use ``jclass._customize()`` to alter the class methods. Using the prototype class as a base class is used mainly to support classes which must be derived from a Python type by design. Use of a base class will produce a RuntimeError if the class has already been created. For non-base class customizers, the customizer will be applied retroactively if the class is already created. Conflicts are resolved by the last customizer applied. Args: clsname (str): name of java class. base (bool, optional): if True this will be a base class. Default is False. """ if not isinstance(clsname, str): raise TypeError("ImplementationFor requires a java classname string") def customizer(cls): hints = getClassHints(clsname) if base: hints.registerClassBase(cls) else: hints.registerClassImplementation(clsname, cls) return cls return customizer def _applyStickyMethods(cls, sticky): for method in sticky: attr = getattr(method, '__joverride__') rename = attr.get('rename', None) name = method.__name__ if rename: orig = type.__getattribute__(cls, name) cls._customize(rename, orig) cls._customize(name, method) def _applyCustomizerImpl(members, proto, sticky, setter): """ (internal) Apply a customizer to a class. This "borrows" methods from a prototype class. Current behavior is: - Copy any string or property. - Copy any callable applying @JOverride if applicable with conflict renaming. - Copy __new__ method. """ for p, v in proto.__dict__.items(): if callable(v) or isinstance(v, _jcopymembers): # Apply JOverride annotation attr = getattr(v, '__joverride__', None) if attr is not None: if attr.get('sticky', False): sticky.append(v) continue # Apply rename rename = attr.get('rename', "_" + p) if p in members and isinstance(members[p], (_jpype._JField, _jpype._JMethod)): setter(rename, members[p]) setter(p, v) def _applyAll(cls, method): applied = set() todo = [cls] while todo: c = todo.pop(0) if c in applied: continue todo.extend(c.__subclasses__()) applied.add(c) method(c) def _applyCustomizerPost(cls, proto): """ (internal) Customize a class after it has been created """ sticky = [] _applyCustomizerImpl(cls.__dict__, proto, sticky, lambda p, v: cls._customize(p, v)) # Merge sticky into existing __jclass_init__ if len(sticky) > 0: method = proto.__dict__.get('__jclass_init__', None) def init(cls): if method: method(cls) _applyStickyMethods(cls, sticky) cls._customize('__jclass_init__', init) # Apply a customizer to all derived classes if '__jclass_init__' in proto.__dict__: method = proto.__dict__['__jclass_init__'] _applyAll(cls, method) class JClassHints(_jpype._JClassHints): """ ClassHints holds class customizers and conversions. These items can be defined before the JVM is created. """ def __init__(self): self.bases = [] self.implementations = [] self.instantiated = False def registerClassBase(self, base): """ (internal) Add an implementation for a class Use @JImplementationFor(cls, base=True) to access this. """ self.bases.append(base) # Changing the base class in python can break things, # so we will tag this as an error for now. if self.instantiated: raise TypeError( "Base classes must be added before class is created") def registerClassImplementation(self, classname, proto): """ (internal) Add an implementation for a class Use @JImplementationFor(cls) to access this. """ self.implementations.append(proto) # If we have already created a class, apply it retroactively. if self.instantiated: _applyCustomizerPost(_jpype.JClass(classname), proto) def applyCustomizers(self, name, bases, members): """ (internal) Called by JClass and JArray to customize a newly created class.""" # Apply base classes for b in self.bases: bases.insert(0, b) module = name.rsplit('.', 1) if len(module) == 2: members['__module__'] = module[0] # Apply implementations sticky = [] for proto in self.implementations: _applyCustomizerImpl(members, proto, sticky, lambda p, v: members.__setitem__(p, v)) if len(sticky) > 0: method = members.get('__jclass_init__', None) def init(cls): if method is not None: method(cls) _applyStickyMethods(cls, sticky) members['__jclass_init__'] = init def applyInitializer(self, cls): """ (internal) Called after the class is created to apply any customizations required by inherited parents. """ self.instantiated = True if hasattr(cls, '__jclass_init__'): init = [] for base in cls.__mro__: if '__jclass_init__' in base.__dict__: init.insert(0, base.__dict__['__jclass_init__']) for func in init: func(cls) def getClassHints(name): if isinstance(name, _jpype._JClass): name = name.__name__ hints = _jpype._hints.get(name, None) if not hints: hints = JClassHints() _jpype._hints[name] = hints return hints _jpype._hints = {} getClassHints("java.lang.IndexOutOfBoundsException").registerClassBase( IndexError) getClassHints("java.lang.NullPointerException").registerClassBase( ValueError) jpype-1.3.0/jpype/_jexception.py000066400000000000000000000036621405671516700166750ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import _jpype from . import _jcustomizer __all__ = ['JException'] @_jcustomizer.JImplementationFor("java.lang.Throwable", base=True) class JException(_jpype._JException, internal=True): """ Base class for all ``java.lang.Throwable`` objects. Use ``issubclass(cls, JException)`` to test if a class is derived from ``java.lang.Throwable.`` Use ``isinstance(obj, JException)`` to test if an object is a ``java.lang.Throwable``. """ # Included for compatibility with JPype 0.6.3 def message(self): return str(self.getMessage()) # Included for compatibility with JPype 0.6.3 def stacktrace(self): """ Get a string listing the stack frame. Returns: A string with the classic Java ``printStackTrace`` result. """ StringWriter = _jpype.JClass("java.io.StringWriter") PrintWriter = _jpype.JClass("java.io.PrintWriter") sw = StringWriter() pw = PrintWriter(sw) self.printStackTrace(pw) pw.flush() r = sw.toString() sw.close() return r @property def args(self): return self._args # Hook up module resources _jpype.JException = JException jpype-1.3.0/jpype/_jinit.py000066400000000000000000000035171405671516700156410ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import _jpype __all__ = ['onJVMStart'] JInitializers = [] def onJVMStart(func): """Decorator to register a function to be called after JVM is started. This can be used to load module resources that depend on the JVM such as loading classes. If the JVM is not started, the user supplied function is held in a list until the JVM starts. When startJVM is called, all functions on the deferred list are called and the list is cleared. If the JVM is already started, then the function is called immediately. Errors from the function will either be raised immediately if the JVM is started, or from startJVM if the JVM is not yet started. Args: func (callable): a function to call when the JVM is started. """ registerJVMInitializer(func) return func def registerJVMInitializer(func): if not _jpype.isStarted(): JInitializers.append(func) else: # JVM is already started so we are safe to execute immediately. func() def runJVMInitializers(): for func in JInitializers: func() JInitializers.clear() jpype-1.3.0/jpype/_jio.py000066400000000000000000000034651405671516700153070ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** from . import _jcustomizer import sys as _sys from . import _jexception # This contains a customizer for closeable so that we can use the python "with" # statement. @_jcustomizer.JImplementationFor("java.lang.AutoCloseable") class _JCloseable(object): """ Customizer for ``java.lang.AutoCloseable`` and ``java.io.Closeable`` This customizer adds support of the ``with`` operator to all Java classes that implement the Java ``AutoCloseable`` interface. Example: .. code-block:: python from java.nio.files import Files, Paths with Files.newInputStream(Paths.get("foo")) as fd: # operate on the input stream # Input stream closes at the end of the block. """ def __enter__(self): return self def __exit__(self, exception_type, exception_value, traceback): info = _sys.exc_info() try: self.close() except _jexception.JException as jex: # Eat the second exception if we are already handling one. if (info[0] is None): raise jex jpype-1.3.0/jpype/_jio.pyi000066400000000000000000000005471405671516700154560ustar00rootroot00000000000000from types import TracebackType from typing import ContextManager, Optional, Type class _JCloseable(ContextManager['_JCloseable']): def __enter__(self) -> '_JCloseable': ... def __exit__(self, exception_type: Optional[Type[BaseException]], exception_value: Optional[BaseException], traceback: Optional[TracebackType]) -> bool: ... jpype-1.3.0/jpype/_jmethod.py000066400000000000000000000103601405671516700161500ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import _jpype __all__ = [] import _jpype from . import _jclass def _jmethodGetDoc(method, cls, overloads): """Generator for _JMethod.__doc__ property Parameters: method (_JMethod): method to generate doc string for. cls (java.lang.Class): Class holding this method dispatch. overloads (java.lang.reflect.Method[]): tuple holding all the methods that are served by this method dispatch. Returns: The doc string for the method dispatch. """ jcls = _jpype.JClass(cls) if not hasattr(jcls, "__javadoc__"): jcls.__doc__ jd = getattr(jcls, "__javadoc__") if jd is not None: md = jd.methods.get(method.__name__) if md is not None: return str(md) from textwrap import TextWrapper out = [] out.append("Java method dispatch '%s' for '%s'" % (method.__name__, cls.getName())) out.append("") exceptions = [] returns = [] methods = [] classmethods = [] for ov in overloads: modifiers = ov.getModifiers() exceptions.extend(ov.getExceptionTypes()) returnName = ov.getReturnType().getCanonicalName() params = ", ".join([str(i.getCanonicalName()) for i in ov.getParameterTypes()]) if returnName != "void": returns.append(returnName) if modifiers & 8: classmethods.append(" * %s %s(%s)" % (returnName, ov.getName(), params)) else: methods.append(" * %s %s(%s)" % (returnName, ov.getName(), params)) if classmethods: out.append(" Static Methods:") out.extend(classmethods) out.append("") if methods: out.append(" Virtual Methods:") out.extend(methods) out.append("") if exceptions: out.append(" Raises:") for exc in set(exceptions): out.append(" %s: from java" % exc.getCanonicalName()) out.append("") if returns: out.append(" Returns:") words = ", ".join([str(i) for i in set(returns)]) wrapper = TextWrapper(initial_indent=' ', subsequent_indent=' ') out.extend(wrapper.wrap(words)) out.append("") return "\n".join(out) def _jmethodGetAnnotation(method, cls, overloads): """Generator for ``_JMethod.__annotation__`` property Parameters: method (_JMethod): method to generate annotations for. cls (java.lang.Class): Class holding this method dispatch. overloads (java.lang.reflect.Method[]): tuple holding all the methods that are served by this method dispatch. Returns: The dict to use for type annotations. """ returns = [] # Special handling if we have 1 overload if len(overloads) == 1: ov = overloads[0] out = {} for i, p in enumerate(ov.getParameterTypes()): out['arg%d' % i] = _jclass.JClass(p) out['return'] = _jclass.JClass(ov.getReturnType()) return out # Otherwise, we only get the return for ov in overloads: returns.append(ov.getReturnType()) returns = set(returns) if len(returns) == 1: return {"return": _jclass.JClass([i for i in returns][0])} return {} def _jmethodGetCode(method): def call(*args): return method.__call__(*args) return call _jpype.getMethodDoc = _jmethodGetDoc _jpype.getMethodAnnotations = _jmethodGetAnnotation _jpype.getMethodCode = _jmethodGetCode jpype-1.3.0/jpype/_jobject.py000066400000000000000000000074001405671516700161370ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import _jpype __all__ = ['JObject'] class JObject(_jpype._JObject, internal=True): """ Base class for all object instances. It can be used to test if an object is a Java object instance with ``isinstance(obj, JObject)``. Calling ``JObject`` as a function can be used to covert or cast to specific Java type. It will box primitive types and supports an option type to box to. This wrapper functions in three ways. - If the no type is given the object is automatically cast to type best matched given the value. This can be used to create a boxed primitive. ``JObject(JInt(i))`` - If the type is a primitve, the object will be the boxed type of that primitive. ``JObject(1, JInt)`` - If the type is a Java class and the value is a Java object, the object will be cast to the Java class and will be an exact match to the class for the purposes of matching arguments. If the object is not compatible, an exception will be raised. Args: value: The value to be cast into an Java object. type(Optional, type): The type to cast into. Raises: TypeError: If the object cannot be cast to the specified type, or the requested type is not a Java class or primitive. """ def __new__(cls, *args, **kwargs): if len(args) == 0: return _jpype._java_lang_Object() return _JObjectFactory(*args, **kwargs) def _getDefaultJavaObject(obj): """ Determine the type of the object based the type of a value. Python primitives - lookup the type in the table Java primitive - lookup boxed type in the table Java objects - just use their type directly """ tp = type(obj) # handle Python types and Java primitives try: return _jpype._object_classes[tp] except KeyError: pass # handle Class wrappers if isinstance(tp, _jpype._JClass): return tp # handle JProxy instances try: return obj.__javaclass__ except AttributeError: pass raise TypeError( "Unable to determine the default type of `{0}`".format(tp.__name__)) def _JObjectFactory(v=None, tp=None): """ Creates a Java object. If not specified type is determined based on the object. If type type is specified then then it tried to box it. """ if tp is None: # Automatically determine based on the value tp = _getDefaultJavaObject(v) elif isinstance(tp, str): tp = _jpype.JClass(tp) if tp in _jpype._object_classes: if not isinstance(tp, _jpype.JClass): import warnings warnings.warn("Using JObject with a Python type is deprecated.", category=DeprecationWarning, stacklevel=3) tp = _jpype._object_classes[tp] # Given a Java class if isinstance(tp, _jpype._JClass): return tp._cast(v) raise TypeError("Invalid type conversion to %s requested." % tp) # Hook up module resources _jpype.JObject = JObject jpype-1.3.0/jpype/_jpackage.py000066400000000000000000000044051405671516700162660ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import _jpype __all__ = ['JPackage'] class _JPackageMeta(type): def __instancecheck__(self, other): return isinstance(other, _jpype._JPackage) def __subclasscheck__(self, other): return issubclass(other, _jpype._JPackage) class JPackage(_jpype._JPackage, metaclass=_JPackageMeta): """ Gateway for automatic importation of Java classes. This class allows structured access to Java packages and classes. This functionality has been replaced by ``jpype.imports``, but is still useful in some cases. Only the root of the package tree needs to be declared with the ``JPackage`` constructor. Sub-packages will be created on demand. For example, to import the w3c DOM package: .. code-block:: python Document = JPackage('org').w3c.dom.Document Under some situations such as a missing jar file, the resulting object will be a JPackage object rather than the expected java class. This results in rather challanging debugging messages. Due to this restriction, the ``jpype.imports`` module is preferred. To prevent these types of errors, a package can be declares as ``strict`` which prevents expanding package names that do not comply with Java package name conventions. Args: path (str): Path into the Java class tree. Example: .. code-block:: python # Alias into a library google = JPackage("com").google # Access members in the library result = google.common.IntMath.pow(x,m) """ pass jpype-1.3.0/jpype/_jproxy.py000066400000000000000000000177341405671516700160650ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import _jpype __all__ = ["JProxy", "JImplements"] # FIXME the java.lang.method we are overriding should be passes to the lookup function # so we can properly handle name mangling on the override. def _checkInterfaceOverrides(interfaces, overrides): # Verify all methods are overriden for interface in interfaces: for method in interface.class_.getMethods(): if method.getModifiers() & 1024 == 0: continue if not str(method.getName()) in overrides: raise NotImplementedError("Interface '%s' requires method '%s' to be implemented." % ( interface.class_.getName(), method.getName())) def _classOverrides(cls): # Find all class defined overrides overrides = {} for k, v in cls.__dict__.items(): try: attr = object.__getattribute__(v, "__joverride__") overrides[k] = (v, attr) except AttributeError: pass return overrides def _prepareInterfaces(cls, intf): # Convert the interfaces list actualIntf = _convertInterfaces(intf) overrides = _classOverrides(cls) _checkInterfaceOverrides(actualIntf, overrides) return actualIntf def _createJProxyDeferred(cls, *intf): """ (internal) Create a proxy from a Python class with @JOverride notation on methods evaluated at first instantiation. """ def new(tp, *args, **kwargs): # Attach a __jpype_interfaces__ attribute to this class if # one doesn't already exist. actualIntf = getattr(tp, "__jpype_interfaces__", None) if actualIntf is None: actualIntf = _prepareInterfaces(cls, intf) tp.__jpype_interfaces__ = actualIntf return _jpype._JProxy.__new__(tp, None, actualIntf) members = {'__new__': new} # Return the augmented class return type("proxy.%s" % cls.__name__, (cls, _jpype._JProxy), members) def _createJProxy(cls, *intf): """ (internal) Create a proxy from a Python class with @JOverride notation on methods evaluated at declaration. """ actualIntf = _prepareInterfaces(cls, intf) def new(tp, *args, **kwargs): self = _jpype._JProxy.__new__(tp, None, actualIntf) tp.__init__(self, *args, **kwargs) return self members = {'__new__': new} # Return the augmented class return type("proxy.%s" % cls.__name__, (cls, _jpype._JProxy), members) def JImplements(*interfaces, deferred=False, **kwargs): """ Annotation for creating a new proxy that implements one or more Java interfaces. This annotation is placed on an ordinary Python class. The annotation requires a list of interfaces. It must implement all of the java methods for each of the interfaces. Each implemented method should have a @JOverride annotation. The JVM must be running in order to validate the class. Args: interfaces (str*,JClass*): Strings or JClasses for each Java interface this proxy is to implement. Kwargs: deferred (bool): Whether to defer validation of the interfaces and overrides until the first instance instantiation (True) or validate at declaration (False). Deferred validation allows a proxy class to be declared prior to starting the JVM. Validation only occurs once per proxy class, thus there is no performance penalty. Default False. Example: .. code-block:: python @JImplement("java.lang.Runnable") class MyImpl(object): @JOverride def run(self, arg): pass @JImplement("org.my.Interface1", "org.my.Interface2") class MyImpl(object): @JOverride def method(self, arg): pass """ if deferred: def JProxyCreator(cls): return _createJProxyDeferred(cls, *interfaces, **kwargs) else: def JProxyCreator(cls): return _createJProxy(cls, *interfaces, **kwargs) return JProxyCreator def _convertInterfaces(intf): """ (internal) Convert a list of interface names into a list of interfaces suitable for a proxy. """ # Flatten the list intflist = [] for item in intf: if isinstance(item, str) or not hasattr(item, '__iter__'): intflist.append(item) else: intflist.extend(item) # Look up the classes if given as a string actualIntf = set() for item in intflist: if isinstance(item, str): actualIntf.add(_jpype.JClass(item)) else: actualIntf.add(item) # Check that all are interfaces if not actualIntf: raise TypeError("At least one Java interface must be specified") for cls in actualIntf: # If it isn't a JClass, then it cannot be a Java interface if not isinstance(cls, _jpype.JClass): raise TypeError("'%s' is not a Java interface" % type(cls).__name__) # Java concrete and abstract classes cannot be proxied if not issubclass(cls, _jpype.JInterface): raise TypeError("'%s' is not a Java interface" % cls.__name__) return tuple(actualIntf) class _JFromDict(object): def __init__(self, dict): self.dict = dict def __getattribute__(self, name): try: return object.__getattribute__(self, 'dict')[name] except KeyError: pass raise AttributeError("attribute not found") class JProxy(_jpype._JProxy): """ Define a proxy for a Java interface. This is an older style JPype proxy interface that uses either a dictionary or an object instance to implement methods defined in java. The python object can be held by java and its lifespan will continue as long as java holds a reference to the object instance. New code should use ``@JImplements`` annotation as it will support improved type safety and error handling. Name lookups can either made using a dictionary or an object instance. One of these two options must be specified. Args: intf: either a single interface or a list of java interfaces. The interfaces can either be defined by strings or JClass instance. Only interfaces may be used in a proxy, dict (dict[string, callable], optional): specifies a dictionary containing the methods to be called when executing the java interface methods. inst (object, optional): specifies an object with methods whose names matches the java interfaces methods. """ def __new__(cls, intf, dict=None, inst=None, convert=False): # Convert the interfaces actualIntf = _convertInterfaces([intf]) # Verify that one of the options has been selected if dict is not None and inst is not None: raise TypeError("Specify only one of dict and inst") if dict is not None: return _jpype._JProxy(_JFromDict(dict), actualIntf, convert) if inst is not None: return _jpype._JProxy.__new__(cls, inst, actualIntf, convert) raise TypeError("a dict or inst must be specified") @staticmethod def unwrap(obj): if not isinstance(obj, _jpype._JProxy): return obj return obj.__javainst__ jpype-1.3.0/jpype/_jstring.py000066400000000000000000000042171405671516700162020ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import _jpype from . import _jcustomizer __all__ = ['JString'] class JString(_jpype._JObject, internal=True): """ Base class for ``java.lang.String`` objects When called as a function, this class will produce a ``java.lang.String`` object. It can be used to test if an object is a Java string using ``isinstance(obj, JString)``. """ def __new__(cls, *args, **kwargs): if cls != JString: raise TypeError("JString factory cannot be used as base class") cls = _jpype.JClass("java.lang.String") return cls(*args) @_jcustomizer.JImplementationFor("java.lang.String") class _JStringProto(object): def __add__(self, other): return self.concat(other) def __len__(self): return self.length() def __getitem__(self, i): if isinstance(i, slice): return str(self)[i] if i < 0: i += len(self) if i < 0: raise IndexError("Array index is negative") if i >= len(self): raise IndexError("Array index exceeds length") return self.charAt(i) def __contains__(self, other): return self.contains(other) def __hash__(self): if self == None: # lgtm [py/test-equals-none] return hash(None) return self.__str__().__hash__() def __repr__(self): return "'%s'" % self.__str__() _jpype.JString = JString jpype-1.3.0/jpype/_jstring.pyi000066400000000000000000000004271405671516700163520ustar00rootroot00000000000000from typing import Any, Text class _JStringProto(Text): def __add__(self, other: Text) -> Text: ... def __len__(self) -> int: ... def __getitem__(self, i: int) -> Text: ... def __contains__(self, other: Text) -> bool: ... def __hash__(self) -> Any: ... jpype-1.3.0/jpype/_jthread.py000066400000000000000000000061071405671516700161430ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import _jpype from . import _jcustomizer @_jcustomizer.JImplementationFor('java.lang.Thread') class _JThread(object): """ Customizer for ``java.land.Thread`` This adds addition JPype methods to java.lang.Thread to support Python. """ @staticmethod def isAttached(): """ Checks if a thread is attached to the JVM. Python automatically attaches as daemon threads when a Java method is called. This creates a resource in Java for the Python thread. This method can be used to check if a Python thread is currently attached so that it can be disconnected prior to thread termination to prevent leaks. Returns: True if the thread is attached to the JVM, False if the thread is not attached or the JVM is not running. """ return _jpype.isThreadAttachedToJVM() @staticmethod def attach(): """ Attaches the current thread to the JVM as a user thread. User threads that are attached to the JVM will prevent the JVM from shutting down until the thread is terminated or detached. To convert a daemon thread to a main thread, the thread must first be detached. Raises: RuntimeError: If the JVM is not running. """ return _jpype.attachThreadToJVM() @staticmethod def attachAsDaemon(): """ Attaches the current thread to the JVM as a daemon. Daemon threads act as background tasks and do not prevent the JVM from shutdown normally. JPype automatically attaches any threads that call Java resources as daemon threads. To convert a daemon thread to a user thread, the thread must first be detached. Raises: RuntimeError: If the JVM is not running. """ return _jpype.attachThreadAsDaemon() @staticmethod def detach(): """ Detaches a thread from the JVM. This function detaches the thread and frees the associated resource in the JVM. For codes making heavy use of threading this should be used to prevent resource leaks. The thread can be reattached, so there is no harm in detaching early or more than once. This method cannot fail and there is no harm in calling it when the JVM is not running. """ return _jpype.detachThreadFromJVM() jpype-1.3.0/jpype/_jthread.pyi000066400000000000000000000003371405671516700163130ustar00rootroot00000000000000class _JThread: @staticmethod def isAttached() -> bool: ... @staticmethod def attach() -> None: ... @staticmethod def attachAsDaemon() -> None: ... @staticmethod def detach() -> None: ... jpype-1.3.0/jpype/_jvmfinder.py000066400000000000000000000311301405671516700165000ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** # Copyright 2013 Thomas Calmant import os import sys __all__ = ['getDefaultJVMPath', 'JVMNotFoundException', 'JVMNotSupportedException'] try: import winreg except ImportError: winreg = None class JVMNotFoundException(ValueError): """ Exception raised when no JVM was found in the search path. This exception is raised when the all of the places searched did not contain a JVM. The locations searched depend on the machine architecture. To avoid this exception specify the JAVA_HOME environment variable as a valid jre or jdk root directory. """ pass class JVMNotSupportedException(ValueError): """ Exception raised when the JVM is not supported. This exception is raised after a search found a valid Java home directory was found, but the JVM shared library found is not supported. Typically this occures when the JVM does not match the architecture of Python 32 vs 64 bit, or the JVM is older than the version used to compile JPype. """ pass def getDefaultJVMPath(): """ Retrieves the path to the default or first found JVM library Returns: The path to the JVM shared library file Raises: JVMNotFoundException: If there was no JVM found in the search path. JVMNotSupportedException: If the JVM was found was not compatible with Python due to cpu architecture. """ if sys.platform == "win32": finder = WindowsJVMFinder() elif sys.platform == "darwin": finder = DarwinJVMFinder() else: finder = LinuxJVMFinder() return finder.get_jvm_path() class JVMFinder(object): """ JVM library finder base class """ def __init__(self): """ Sets up members """ # Library file name self._libfile = "libjvm.so" # Predefined locations self._locations = ("/usr/lib/jvm", "/usr/java") # Search methods self._methods = (self._get_from_java_home, self._get_from_known_locations) def find_libjvm(self, java_home): """ Recursively looks for the given file Parameters: java_home(str): A Java home folder filename(str): filename: Name of the file to find Returns: The first found file path, or None """ non_supported_jvm = ('cacao', 'jamvm') found_non_supported_jvm = False # Look for the file for root, _, names in os.walk(java_home): if self._libfile in names: # Found it, but check for non supported jvms candidate = os.path.split(root)[1] if candidate in non_supported_jvm: found_non_supported_jvm = True continue # maybe we will find another one? return os.path.join(root, self._libfile) if found_non_supported_jvm: raise JVMNotSupportedException("Sorry '{0}' is known to be " "broken. Please ensure your " "JAVA_HOME contains at least " "another JVM implementation " "(eg. server)" .format(candidate)) # File not found raise JVMNotFoundException("Sorry no JVM could be found. " "Please ensure your JAVA_HOME " "environment variable is pointing " "to correct installation.") def find_possible_homes(self, parents): """ Generator that looks for the first-level children folders that could be Java installations, according to their name Parameters: parents (str[]): A list of parent directories Returns: A list of the possible JVM installation folders """ homes = [] java_names = ('jre', 'jdk', 'java') for parent in parents: # Fast exit if folder does not exist if not os.path.exists(parent): continue for childname in sorted(os.listdir(parent)): # Compute the real path path = os.path.realpath(os.path.join(parent, childname)) if path in homes or not os.path.isdir(path): # Already known path, or not a directory -> ignore continue # Check if the path seems OK real_name = os.path.basename(path).lower() for java_name in java_names: if java_name in real_name: # Correct JVM folder name homes.append(path) yield path break def check(self, jvm): """ Check if the jvm is valid for this architecture. This method should be overriden for each architecture. Raises: JVMNotSupportedException: If the jvm is not supported. """ pass def get_jvm_path(self): """ Retrieves the path to the default or first found JVM library Returns: The path to the JVM shared library file Raises: ValueError: No JVM library found or No Support JVM found """ jvm_notsupport_ext = None for method in self._methods: try: jvm = method() # If found check the architecture if jvm: self.check(jvm) except NotImplementedError: # Ignore missing implementations pass except JVMNotFoundException: # Ignore not successful methods pass except JVMNotSupportedException as e: jvm_notsupport_ext = e else: if jvm is not None: return jvm if jvm_notsupport_ext is not None: raise jvm_notsupport_ext raise JVMNotFoundException("No JVM shared library file ({0}) " "found. Try setting up the JAVA_HOME " "environment variable properly." .format(self._libfile)) def _get_from_java_home(self): """ Retrieves the Java library path according to the JAVA_HOME environment variable Returns: The path to the JVM library, or None """ # Get the environment variable java_home = os.getenv("JAVA_HOME") if java_home and os.path.exists(java_home): # Get the real installation path java_home = os.path.realpath(java_home) if not os.path.exists(java_home): java_home = os.getenv("JAVA_HOME") # Look for the library file return self.find_libjvm(java_home) def _get_from_known_locations(self): """ Retrieves the first existing Java library path in the predefined known locations Returns: The path to the JVM library, or None """ for home in self.find_possible_homes(self._locations): jvm = self.find_libjvm(home) if jvm is not None: return jvm class LinuxJVMFinder(JVMFinder): """ Linux JVM library finder class """ def __init__(self): """ Sets up members """ # Call the parent constructor JVMFinder.__init__(self) # Java bin file self._java = "/usr/bin/java" # Library file name self._libfile = "libjvm.so" # Predefined locations self._locations = ("/usr/lib/jvm", "/usr/java", "/opt/sun") # Search methods self._methods = (self._get_from_java_home, self._get_from_bin, self._get_from_known_locations) def _get_from_bin(self): """ Retrieves the Java library path according to the real installation of the java executable :return: The path to the JVM library, or None """ # Find the real interpreter installation path java_bin = os.path.realpath(self._java) if os.path.exists(java_bin): # Get to the home directory java_home = os.path.abspath(os.path.join(os.path.dirname(java_bin), '..')) # Look for the JVM library return self.find_libjvm(java_home) class DarwinJVMFinder(LinuxJVMFinder): """ Mac OS X JVM library finder class """ def __init__(self): """ Sets up members """ # Call the parent constructor LinuxJVMFinder.__init__(self) # Library file name self._libfile = "libjli.dylib" self._methods = list(self._methods) self._methods.append(self._javahome_binary) # Predefined locations self._locations = ('/Library/Java/JavaVirtualMachines',) def _javahome_binary(self): """ for osx > 10.5 we have the nice util /usr/libexec/java_home available. Invoke it and return its output. It seems this tool has been removed in osx 10.9. """ import platform import subprocess from distutils.version import StrictVersion current = StrictVersion(platform.mac_ver()[0][:4]) if current >= StrictVersion('10.6') and current < StrictVersion('10.9'): return subprocess.check_output( ['/usr/libexec/java_home']).strip() def _checkJVMArch(jvmPath, maxsize=sys.maxsize): import struct IMAGE_FILE_MACHINE_I386 = 332 IMAGE_FILE_MACHINE_IA64 = 512 IMAGE_FILE_MACHINE_AMD64 = 34404 is64 = maxsize > 2**32 with open(jvmPath, "rb") as f: s = f.read(2) if s != b"MZ": raise JVMNotSupportedException("JVM not valid") f.seek(60) s = f.read(4) header_offset = struct.unpack(" JDBCTYPE def SETTERS_BY_META(cx, meta, col, ptype): """ Option for setters to use the metadata of the parameters. On some databases this option is useless as they do not track parameter types. This method can be cached for faster performance when lots of parameters. Usually types can only be determined accurately on inserts into defined columns. """ return _default_map[_registry[meta.getParameterType(col + 1)]] SETTERS_BY_META._cachable = True def SETTERS_BY_TYPE(cx, meta, col, ptype): """ Option for setters to use the type of the object passed. This option looks at the type of the parameter being passed from Python after adapters have been applied to determine the best setter. """ return _default_setters.get(ptype, None) # Getters take (connection, meta, col) -> JDBCTYPE def GETTERS_BY_TYPE(cx, meta, idx): """ Option for getters to determine column type by the JDBC type. This option is the default option that uses the type code supplied in the meta data. On some databases it is better to use the name. If the type code is OTHER, it will attempt to find a type by name. New types can be created with JDBCType for database specific types. """ tp = _registry[meta.getColumnType(idx + 1)] if tp == OTHER: # Other may be found by name name = str(meta.getColumnTypeName(idx + 1)).upper() return _registry.get(name, tp) return _default_map[tp] def GETTERS_BY_NAME(cx, meta, idx): """ Option to getters to determine column type by the column name. This option uses the column name to select the type. It looks up the column type name, converts it to uppercase, and then searches for a matchine type. It falls back to the type code meta information if the typename can not be found in the registery. New types can be created using JDBCType for database specific types such as ``JSON``. """ name = str(meta.getColumnTypeName(idx + 1)).upper() tp = _registry.get(name, None) if tp is None: tp = _registry[meta.getColumnType(idx + 1)] return _default_map.get(tp, tp) ############################################################################### # Exceptions class Warning(Exception): """Exception raised for important warnings like data truncations while inserting, etc. """ pass class Error(Exception): """Exception that is the base class of all other error exceptions. You can use this to catch all errors with one single except statement. Warnings are not considered errors and thus should not use this class as base. """ pass class InterfaceError(Error, TypeError): """ Exception raised for errors that are related to the database interface rather than the database itself.""" pass class DatabaseError(Error): """ Exception raised for errors that are related to the database.""" pass class DataError(DatabaseError): """ Exception raised for errors that are due to problems with the processed data like division by zero, numeric value out of range, etc.""" pass class OperationalError(DatabaseError): """ Exception raised for errors that are related to the database's operation and not necessarily under the control of the programmer, e.g. an unexpected disconnect occurs, the data source name is not found, a transaction could not be processed, a memory allocation error occurred during processing, etc.""" pass class IntegrityError(DatabaseError): """ Exception raised when the relational integrity of the database is affected, e.g. a foreign key check fails.""" pass class InternalError(DatabaseError): """ Exception raised when the database encounters an internal error, e.g. the cursor is not valid anymore, the transaction is out of sync, etc.""" pass class ProgrammingError(DatabaseError): """ Exception raised for programming errors, e.g. table not found or already exists, syntax error in the SQL statement, wrong number of parameters specified, etc.""" pass class NotSupportedError(DatabaseError): """ Exception raised in case a method or database API was used which is not supported by the database, e.g. requesting a .rollback() on a connection that does not support transaction or has transactions turned off. """ pass class _UnsupportedTypeError(InterfaceError, TypeError): pass ############################################################################### # Connection _default = object() def connect(dsn, *, driver=None, driver_args=None, adapters=_default, converters=_default, getters=GETTERS_BY_TYPE, setters=SETTERS_BY_TYPE, **kwargs): """ Create a connection to a database. Arguments to the driver depend on the database type. Args: dsn (str): The database connection string for JDBC. driver (str, optional): A JDBC driver to load. driver_args: Arguments to the driver. This may either be a dict, java.util.Properties. If not supplied, kwargs are used as as the parameters for the JDBC connection. *kwargs: Arguments to the driver if not supplied as driver_args. Raises: Error if the connection cannot be established. Returns: A new connection if successful. """ Properties = _jpype.JClass("java.util.Properties") if driver: _jpype.JClass('java.lang.Class').forName(driver).newInstance() DM = _jpype.JClass('java.sql.DriverManager') # User is supplying Java properties if isinstance(driver_args, Properties): connection = DM.getConnection(dsn, driver_args) # User is supplying a mapping that can be converted Properties elif isinstance(driver_args, typing.Mapping): info = Properties() for k, v in driver_args.items(): info.setProperty(k, v) connection = DM.getConnection(dsn, info) # User supplied nothing elif driver_args is None: connection = DM.getConnection(dsn) # Otherwise use the kwargs else: info = Properties() for k, v in kwargs.items(): info.setProperty(k, v) connection = DM.getConnection(url, info) return Connection(connection, adapters, converters, setters, getters) class Connection(object): """ Connection provides access to a JDBC database. Connections are managed and can be as part of a Python with statement. Connections close automatically when they are garbage collected, at the end of a with statement scope, or when manually closed. Once a connection is closed all operations using the database will raise an Error. """ Error = Error Warning = Warning InterfaceError = InterfaceError DatabaseError = DatabaseError InternalError = InternalError OperationalError = OperationalError ProgrammingError = ProgrammingError IntegrityError = IntegrityError DataError = DataError NotSupportedError = NotSupportedError def __init__(self, jconnection, adapters, converters, setters, getters): self._jcx = jconnection # Required by PEP 249 # https://www.python.org/dev/peps/pep-0249/#commit self._jcx.setAutoCommit(False) # Handle defaults if adapters is _default: adapters = dict(_default_adapters) if adapters is None: adapters = {} if converters is _default: converters = dict(_default_converters) if converters is None: converters = {} self._closed = False self._batch = jconnection.getMetaData().supportsBatchUpdates() self._adapters = adapters self._converters = converters self._getters = getters self._setters = setters @property def adapters(self): """ Adapters are used to convert Python types into JDBC types. Adaptors are stored in a mapping from incoming type to an adapter function. Adapters set on a connection apply only to that connection. Adapters can be overriden when calling the ``.execute*()`` method. Adapters can also be set on the JDBC types directly. """ return self._adapters @adapters.setter def adapters(self, v): if v is None: v = {} if not isinstance(v, typing.Mapping): raise _UnsupportedTypeError("Mapping is required") self._adapters = v @property def converters(self): """ Converters are applied when retrieving a JDBC type from the database. """ return self._converters @converters.setter def converters(self, v): if v is None: v = {} if not isinstance(v, typing.Mapping): raise _UnsupportedTypeError("Mapping is required") self._converters = v @property def getters(self): """ Getters are used to retrieve JDBC types from the database following a ``.fetch*()``. Getters should be a function taking (connection, meta, col) -> JDBCTYPE """ return self._getters # Setters take (connection, meta, col, type) -> JDBCTYPE @getters.setter def getters(self, v): self._getters = v @property def setters(self): """ Setter are used to set parameters to ``.execute*()`` methods. Setters should be a function taking (connection, meta, col, type) -> JDBCTYPE """ return self._setters @setters.setter def setters(self, v): self._setters = v def __setattr__(self, name, value): if isinstance(vars(type(self)).get(name, None), property): return object.__setattr__(self, name, value) if not name.startswith("_"): raise AttributeError("'%s' cannot be set" % name) object.__setattr__(self, name, value) def _close(self): if self._closed or not _jpype.isStarted(): return if not self._jcx.isClosed(): self._jcx.close() self._closed = True def __enter__(self): return self def __exit__(self, exception_type, exception_value, traceback): self._close() def __del__(self): try: self._close() except Exception: # pragma: no cover pass def close(self): """ Close the connection immediately (rather than whenever .__del__() is called). The connection will be unusable from this point forward; an Error (or subclass) exception will be raised if any operation is attempted with the connection. The same applies to all cursor objects trying to use the connection. Note that closing a connection without committing the changes first will cause an implicit rollback to be performed. """ self._validate() self._close() def commit(self): """Commit any pending transaction to the database. Calling commit on a cooonection that does not support the operation will raise NotSupportedError. """ self._validate() if self._jcx.getAutoCommit(): raise NotSupportedError("Autocommit is enabled") try: self._jcx.commit() except Exception as ex: # pragma: no cover raise OperationalError(ex.message()) from ex def rollback(self): """Rollback the transaction. This method is optional since not all databases provide transaction support. Calling rollback on a cooonection that does not support will raise NotSupportedError. In case a database does provide transactions this method causes the database to roll back to the start of any pending transaction. Closing a connection without committing the changes first will cause an implicit rollback to be performed. """ self._validate() if self._jcx.getAutoCommit(): raise NotSupportedError("Autocommit is enabled", self.autocommit) try: self._jcx.rollback() except Exception as ex: # pragma: no cover raise OperationalError(ex.message()) from ex def cursor(self): """ Return a new Cursor Object using the connection. """ self._validate() return Cursor(self) def _validate(self): if self._closed or self._jcx.isClosed(): raise ProgrammingError @property def connection(self): """ Get the JDBC connection that is backing this Python Connection object. This can be used to retrieve additional metadata and other features that are outside of the scope of the DBAPI driver. """ return self._jcx @property def autocommit(self): """ bool: Property controlling autocommit behavior. By default connects are not autocommit. Setting autocommit will result in commit and rollback producing a ProgrammingError. """ self._validate() return self._jcx.getAutoCommit() @autocommit.setter def autocommit(self, enabled): self._validate() self._jcx.setAutoCommit(enabled) @property def typeinfo(self): """ list: The list of types that are supported by this driver. This is useful to find out the capabilities of the driver. """ self._validate() out = {} metadata = self._jcx.getMetaData() with metadata.getTypeInfo() as resultSet: while (resultSet.next()): try: key = str(resultSet.getString("TYPE_NAME")) out[key] = _registry[resultSet.getInt("DATA_TYPE")] except KeyError as ex: # pragma: no cover raise DatabaseError("Unknown data type '%s'" % key) from ex return out ############################################################################### # Cursor class Cursor(object): """ Cursors are used to execute queries and retrieve results. Part PreparedStatement, part ResultSet, Cursors are a mixture of both. The native resultSet can be accessed with ``resultSet``. Cursors are managed and can be as part of a Python with statement. Cursors close automatically when they are garbage collected, at the end of a with statement scope, or when manually closed. Once a cursor is closed all operations using the database will raise an Error. """ def __init__(self, connection): if not isinstance(connection, Connection): raise TypeError self._connection = connection self._jcx = connection._jcx self._resultSet = None self._statement = None self._rowcount = -1 self._arraysize = 1 self._description = None self._closed = False self._resultGetters = None self._thread = threading.get_ident() self._last = None def _close(self): if self._closed or not _jpype.isStarted(): return self._finish() self._closed = True def _setParams(self, params): cx = self._connection meta = self._statement.getParameterMetaData() count = meta.getParameterCount() types = self._parameterTypes if types is None: types = [None] * count if isinstance(params, str): raise _UnsupportedTypeError("parameters must be a sequence of values") if isinstance(params, typing.Sequence): if count != len(params): raise ProgrammingError("incorrect number of parameters (%d!=%d)" % (count, len(params))) for i in range(len(params)): p = params[i] # Find and apply the adapter a = cx._adapters.get(type(p), None) if a is not None: p = a(p) # Find the setter if types[i] is None: s = cx._setters(cx, meta, i, type(p)) types[i] = s if s is None: raise _UnsupportedTypeError("no setter found for '%s'" % type(p).__name__) s.set(self._statement, i + 1, p) # Cache if hasattr(cx._setters, "_cachable"): self._parameterTypes = types elif isinstance(params, typing.Mapping): raise _UnsupportedTypeError("mapping parameters not supported") elif isinstance(params, typing.Iterable): for i, p in enumerate(params): if i >= count: raise ProgrammingError("incorrect number of parameters (%d!=%d)" % (count, i + 1)) # Find and apply the adapter a = cx._adapters.get(type(p), None) if a is not None: p = a(p) # Find the setter if types[i] is None: s = cx._setters(cx, meta, i, type(p)) types[i] = s if s is None: raise _UnsupportedTypeError("no setter found for '%s'" % type(p).__name__) s.set(self._statement, i + 1, p) if count != i + 1: raise ProgrammingError("incorrect number of parameters (%d!=%d)" % (count, i + 1)) # Cache if hasattr(cx._setters, "_cachable"): self._parameterTypes = types else: raise _UnsupportedTypeError("'%s' parameters not supported" % (type(params).__name__)) # pragma: no cover def _onResultSet(self, rs): meta = rs.getMetaData() self._resultSet = rs self._resultSetMeta = meta self._resultSetCount = meta.getColumnCount() self._columnTypes = None def _fetchRow(self, converters): cx = self._connection count = self._resultSetCount meta = self._resultSetMeta byPosition = False if converters is _default: converters = cx._converters if isinstance(converters, typing.Sequence): if len(converters) != count: raise ProgrammingError("converter list size incorrect") byPosition = True # Get all the column types if self._columnTypes is None: gk = cx._getters # We need the type information for the columns self._columnTypes = [gk(cx, meta, i) for i in range(count)] if len(self._columnTypes) != count: raise ProgrammingError("incorrect number of columns") try: row = [] for idx in range(count): tp = self._columnTypes[idx] # Fetch the value value = tp.get(self._resultSet, idx + 1, False) if value is None or converters is None: row.append(value) elif byPosition: # find the column converter by type converter = converters[idx] row.append(converter(value)) else: # find the column converter by type converter = cx._converters.get(type(value), _nop) row.append(converter(value)) return row except TypeError as ex: raise _UnsupportedTypeError(str(ex)) from ex def _validate(self): """ Called before any method that requires the statement to be open. """ if self._closed or self._jcx.isClosed(): raise ProgrammingError("Cursor is closed") if threading.get_ident() != self._thread: raise ProgrammingError("Threading error") def _check_executed(self): """ Called before any method that requires the resultSet to be open. """ if self._closed or self._jcx.isClosed() or threading.get_ident() != self._thread: raise ProgrammingError("Cursor is closed") if self._resultSet is None: raise ProgrammingError("execute() first") def _finish(self): if self._resultSet is not None: self._resultSet.close() self._resultSet = None if self._statement is not None: self._statement.close() self._statement = None self._rowcount = -1 self._description = None self._last = None @property def resultSet(self): """ Get the Java result set if available. The object will be closed on the next call to ``.execute*()``. """ return self._resultSet @property def parameters(self): """ (extension) Parameters is read-only attribute is a sequence of 6-item sequences. Each of these sequences contains information describing one result column: - type_name - jdbc_type - parameter_mode (1=in, 2=in/out, 4=out) - precision - scale - null_ok This can only be used after execute or callproc. """ desc = [] if not self._statement: raise ProgrammingError("No statement") meta = self._statement.getParameterMetaData() for i in range(1, meta.getParameterCount() + 1): desc.append((str(meta.getParameterTypeName(i)), _registry[meta.getParameterType(i)], meta.getParameterMode(i), meta.getPrecision(i), meta.getScale(i), meta.isNullable(i),)) return desc @property def description(self): """ Description is read-only attribute is a sequence of 7-item sequences. Each of these sequences contains information describing one result column: - name - type_code - display_size - internal_size - precision - scale - null_ok This can only be used if the last query produced a result set. """ if self._description is not None: return self._description desc = [] if not self._resultSet: return None meta = self._resultSet.getMetaData() for i in range(1, meta.getColumnCount() + 1): size = meta.getColumnDisplaySize(i) desc.append((str(meta.getColumnName(i)), str(meta.getColumnTypeName(i)), size, size, meta.getPrecision(i), meta.getScale(i), meta.isNullable(i),)) self._description = desc return desc @property def rowcount(self): """ This read-only attribute specifies the number of rows that the last .execute*() affected (for DML statements like UPDATE or INSERT). The attribute is -1 in case no .execute*() has been performed on the cursor or the rowcount of the last operation is cannot be determined by the interface. JDBC does not support getting the number of rows returned from SELECT, so for most drivers rowcount will be -1 after a SELECT statement. """ return self._rowcount def close(self): """ Close the cursor now (rather than whenever __del__ is called). The cursor will be unusable from this point forward; an Error (or subclass) exception will be raised if any operation is attempted with the cursor. """ self._validate() self._close() def callproc(self, procname, parameters=(), *, types=None): """ Call a stored procedure. (Not all JDBC drivers support this method) Call a stored database procedure with the given name. The sequence of parameters must contain one entry for each argument that the procedure expects. The result of the call is returned as modified copy of the input sequence. Input parameters are left untouched, output and input/output parameters replaced with possibly new values. For type output and input/output arguments, it is best to use types keyword argument to select the appropriate getters for the returned arguments. Converters are applied to output parameters. The procedure may also provide a result set as output. This must then be made available through the standard .fetch*() methods. """ try: self._validate() self._finish() if not isinstance(procname, str): raise _UnsupportedTypeError("procname must be str, not '%s'" % type(procname).__name__) if not isinstance(parameters, typing.Sequence): raise _UnsupportedTypeError("parameters must be sequence, not '%s'" % type(procname).__name__) query = "{CALL %s(%s)}" % (procname, ",".join("?" * len(parameters))) try: self._statement = self._jcx.prepareCall(query) except _SQLException as ex: raise ProgrammingError(ex.message()) from ex # This is a special one as we need to deal with in and out arguments out = list(parameters) cx = self._connection meta = self._statement.getParameterMetaData() count = meta.getParameterCount() if types is None: types = [None] * count else: if len(types) != count: raise ProgrammingError("expected '%d' types, got '%d'" % (count, len(types))) for i in range(count): # Lookup the JDBC Type p = parameters[i] a = cx._adapters.get(type(p), None) if a is not None: p = a(p) if types[i] is None: types[i] = cx._setters(cx, meta, i, type(p)) jdbcType = types[i] if jdbcType is None: raise _UnsupportedTypeError("no setter found for '%s'" % type(p).__name__) mode = meta.getParameterMode(i + 1) if mode == 1: jdbcType.set(self._statement, i + 1, p) types[i] = None if mode == 2: jdbcType.set(self._statement, i + 1, p) self.registerOutParameter(i + 1, jdbcType._code) if mode == 4: self.registerOutParameter(i + 1, jdbcType._code) if self._statement.execute(): self._onResultSet(self._statement.getResultSet()) self._rowcount = self._statement.getUpdateCount() for i, t in enumerate(types): if t is None: continue # Find the converter to apply to the column value = t.get(self._statement, i + 1, True) # FIXME how do we get a converv converter = cx._converters[type(value)] out[i] = converter(value) return out # Restore the defaults except Exception as ex: self._converters = self._connection._converters self._getters = self._connection._getters raise ex finally: self._adapters = self._connection._adapters self._setters = self._connection._setters def execute(self, operation, parameters=None, *, types=None, keys=False): """ Prepare and execute a database operation (query or command). Parameters may be provided as sequence and will be bound to variables in the operation. Variables are specified in a qmark notation. JDBC does not support mapping style parameters. After executing a statement, the rowcount will be updated. If the statement has no result set then the rowcount will be -1. A statement can produce multiple result sets. Use ``.nextset()`` to traverse the sets. Parameters: operation (str): A statement to be executed. parameters (list, optional): A list of parameters for the statement. The number of parameters much match the number required by the statement or an Error will be raised. keys (bool, optional): Specify if the keys should be available to retrieve. (Default False) Returns: This cursor. """ self._last = None self._parameterTypes = types self._validate() self._finish() if parameters is None: parameters = () if not isinstance(parameters, (typing.Sequence, typing.Iterable, typing.Iterator)): raise _UnsupportedTypeError("parameters are of unsupported type '%s'" % type(parameters).__name__) # complete the previous operation try: if keys: self._statement = self._jcx.prepareStatement(operation, 1) else: self._statement = self._jcx.prepareStatement(operation) except TypeError as ex: raise _UnsupportedTypeError(str(ex)) except _SQLException as ex: raise ProgrammingError(ex.message()) from ex self._executeone(parameters) return self def _executeone(self, params): self._setParams(params) if self._statement.execute(): self._onResultSet(self._statement.getResultSet()) self._rowcount = self._statement.getUpdateCount() return self._rowcount def executemany(self, operation, seq_of_parameters, *, types=None, keys=False): """ Prepare a database operation (query or command) and then execute it against all parameter sequences or mappings found in the sequence seq_of_parameters. Modules are free to implement this method using multiple calls to the .execute() method or by using array operations to have the database process the sequence as a whole in one call. Use of this method for an operation which produces one or more result sets constitutes undefined behavior, and the implementation is permitted (but not required) to raise an exception when it detects that a result set has been created by an invocation of the operation. The same comments as for .execute() also apply accordingly to this method. Args: operation (str): A statement to be executed. seq_of_parameters (list, optional): A list of lists of parameters for the statement. The number of parameters much match the number required by the statement or an Error will be raised. keys (bool, optional): Specify if the keys should be available to retrieve. (Default False) For drivers that do not support batch updates only that last key will be returned. Returns: This cursor. """ self._last = None self._parameterTypes = types self._validate() if seq_of_parameters is None: seq_of_parameters = () # complete the previous operation self._finish() try: if keys: self._statement = self._jcx.prepareStatement(operation, 1) else: self._statement = self._jcx.prepareStatement(operation) except TypeError as ex: raise _UnsupportedTypeError(str(ex)) except _SQLException as ex: raise ProgrammingError("Failed to prepare '%s'" % operation) from ex if self._connection._batch: return self._executeBatch(seq_of_parameters) else: # pragma: no cover return self._executeRepeat(seq_of_parameters) def _executeBatch(self, seq_of_parameters): if isinstance(seq_of_parameters, typing.Iterable): for params in seq_of_parameters: self._setParams(params) self._statement.addBatch() else: raise _UnsupportedTypeError("'%s' is not supported" % type(seq_of_parameters).__name__) try: counts = self._statement.executeBatch() except _SQLException as ex: # pragma: no cover raise ProgrammingError(ex.message()) from ex self._rowcount = sum(counts) if self._rowcount < 0: # pragma: no cover self._rowcount = -1 return self def _executeRepeat(self, seq_of_parameters): # pragma: no cover counts = [] if isinstance(seq_of_parameters, typing.Iterable): for params in seq_of_parameters: counts.append(self._executeone(params)) elif isinstance(seq_of_parameters, typing.Iterator): while True: try: params = next(seq_of_parameters) counts.append(self._executeone(params)) except StopIteration: break else: raise _UnsupportedTypeError("'%s' is not supported" % str(type(seq_of_parameters))) self._rowcount = sum(counts) if self._rowcount < 0: self._rowcount = -1 return self def fetchone(self, *, types=None, converters=_default): """ Fetch the next row of a query result set, returning a single sequence, or None when no more data is available. An Error (or subclass) exception is raised if the previous call to .execute*() did not produce any result set or no call was issued yet. """ self._check_executed() if not self._resultSet.next(): return None if types is not None: self._columnTypes = types return self._fetchRow(converters) def fetchmany(self, size=None, *, types=None, converters=_default): """ Fetch multiple results. Fetch the next set of rows of a query result, returning a sequence of sequences (e.g. a list of tuples). An empty sequence is returned when no more rows are available. The number of rows to fetch per call is specified by the parameter. If it is not given, the cursor's arraysize determines the number of rows to be fetched. The method should try to fetch as many rows as indicated by the size parameter. If this is not possible due to the specified number of rows not being available, fewer rows may be returned. An Error (or subclass) exception is raised if the previous call to ``.execute*()`` did not produce any result set or no call was issued yet. Note there are performance considerations involved with the size parameter. For optimal performance, it is usually best to use the .arraysize attribute. If the size parameter is used, then it is best for it to retain the same value from one ``.fetchmany()`` call to the next. """ self._check_executed() if size is None: size = self._arraysize # Set a fetch size self._resultSet.setFetchSize(size) rows = [] if types is not None: self._columnTypes = types for i in range(size): if not self._resultSet.next(): break row = self._fetchRow(converters) rows.append(row) # Restore the default fetch size self._resultSet.setFetchSize(0) return rows def fetchall(self, *, types=None, converters=_default): """ Fetch all (remaining) rows of a query result, returning them as a sequence of sequences (e.g. a list of tuples). Note that the cursor's arraysize attribute can affect the performance of this operation. An Error (or subclass) exception is raised if the previous call to ``.execute*()`` did not produce any result set or no call was issued yet. """ self._check_executed() # Set a fetch size rows = [] if types is not None: self._columnTypes = types while self._resultSet.next(): row = self._fetchRow(converters) rows.append(row) return rows def __iter__(self): """ (extension) Iterate through a cursor one record at a time. """ self._check_executed() # Set a fetch size while self._resultSet.next(): yield self._fetchRow(_default) def nextset(self): """ Get the next result set in this cursor. Not all databases support multiple result sets. This method will make the cursor skip to the next available set, discarding any remaining rows from the current set. If there are no more sets, the method returns None. Otherwise, it returns a true value and subsequent calls to the ``.fetch*()`` methods will return rows from the next result set. An Error (or subclass) exception is raised if the previous call to ``.execute*()`` did not produce any result set or no call was issued yet. """ self._resultSet.close() if self._statement.getMoreResults(): # pragma: no cover self._onResultSet(_statement.getResultSet()) return True else: self._rowcount = self._statement.getUpdateCount() return None @property def arraysize(self): """ Specify the number of rows to fetch with ``.fetchmany()``. This read/write attribute specifies the number of rows to fetch at a time with ``.fetchmany()``. It defaults to 1 meaning to fetch a single row at a time. """ return self._arraysize @arraysize.setter def arraysize(self, sz): self._arraysize = sz @property def lastrowid(self): """ Get the id of the last row inserted. This is not supported on all JDBC drivers. The ``.execute*()`` must have been executed with keys set to True. Returns: None if there is no rowid, the rowid if only one row was inserted, or a list of row ids if multiple rows were inserted. """ if self._last is not None: return self._last with self._statement.getGeneratedKeys() as rs: if rs.isClosed(): return self._last last = [] while rs.next(): last.append(rs.getLong(1)) if len(last) == 0: return None if len(last) == 1: self._last = last[0] return last[0] self._last = last return last def setinputsizes(self, sizes): """ This can be used before a call to .execute*() to predefine memory areas for the operation's parameters. sizes is specified as a sequence — one item for each input parameter. The item should be a Type Object that corresponds to the input that will be used, or it should be an integer specifying the maximum length of a string parameter. If the item is None, then no predefined memory area will be reserved for that column (this is useful to avoid predefined areas for large inputs). This method would be used before the .execute*() method is invoked. (not implemented) """ pass def setoutputsize(self, size, column=None): """ Set a column buffer size for fetches of large columns (e.g. LONGs, BLOBs, etc.). The column is specified as an index into the result sequence. Not specifying the column will set the default size for all large columns in the cursor. (not implemented) """ pass def __del__(self): try: self._close() except Exception: # pragma: no cover pass def __enter__(self): return self def __exit__(self, exception_type, exception_value, traceback): self._close() ############################################################################### # Factories def Date(year, month, day): """ This function constructs an object holding a date value. """ return _jpype.JClass('java.sql.Date')(year - 1900, month - 1, day) def Time(hour, minute, second): """ This function constructs an object holding a time value. """ return _jpype.JClass('java.sql.Time')(hour, minute, second) def Timestamp(year, month, day, hour, minute, second, nano=0): """ This function constructs an object holding a time stamp value. """ return _jpype.JClass('java.sql.Timestamp')(year - 1900, month - 1, day, hour, minute, second, nano) def DateFromTicks(ticks): """ This function constructs an object holding a date value from the given ticks value (number of seconds since the epoch; see the documentation of the standard Python time module for details). """ return Date(*time.localtime(ticks)[:3]) def TimeFromTicks(ticks): """ This function constructs an object holding a time value from the given ticks value (number of seconds since the epoch; see the documentation of the standard Python time module for details). """ return Time(*time.localtime(ticks)[3:6]) def TimestampFromTicks(ticks): """ This function constructs an object holding a time stamp value from the given ticks value (number of seconds since the epoch; see the documentation of the standard Python time module for details). """ return Timestamp(*time.localtime(ticks)[:6]) def Binary(data): """ This function constructs an object capable of holding a binary (long) string value. """ return _jtypes.JArray(_jtypes.JByte)(data) # SQL NULL values are represented by the Python None singleton on input and output. _accepted = set(["exact", "implicit"]) def _populateTypes(): global _SQLException, _SQLTimeoutException _SQLException = _jpype.JClass("java.sql.SQLException") _SQLTimeoutException = _jpype.JClass("java.sql.SQLTimeoutException") cs = _jpype.JClass("java.sql.CallableStatement") ps = _jpype.JClass("java.sql.PreparedStatement") rs = _jpype.JClass("java.sql.ResultSet") for v in _types: v._initialize(cs, ps, rs) java = _jpype._JPackage("java") byteArray = _jpype.JArray(_jtypes.JByte) _default_setters[java.lang.String] = STRING _default_setters[java.sql.Date] = DATE _default_setters[java.sql.Time] = TIME _default_setters[java.sql.Timestamp] = TIMESTAMP _default_setters[byteArray] = BINARY _default_setters[java.math.BigDecimal] = DECIMAL _default_setters[_jtypes.JFloat] = REAL _default_setters[_jtypes.JDouble] = DOUBLE _default_setters[_jtypes.JBoolean] = BOOLEAN _default_setters[_jtypes.JShort] = INTEGER _default_setters[_jtypes.JInt] = INTEGER _default_setters[_jtypes.JLong] = BIGINT _default_setters[bool] = BOOLEAN _default_setters[int] = BIGINT _default_setters[float] = DOUBLE _default_setters[str] = STRING _default_setters[memoryview] = BINARY _default_setters[bytes] = BINARY _default_setters[bytearray] = BINARY _default_setters[type(None)] = OBJECT _default_setters[java.sql.Clob] = CLOB _default_setters[java.sql.Blob] = BLOB _default_setters[datetime.datetime] = TIMESTAMP _default_setters[datetime.date] = DATE _default_setters[datetime.time] = TIME _default_converters[java.lang.String] = str _default_converters[java.sql.Date] = _asPython _default_converters[java.sql.Time] = _asPython _default_converters[java.sql.Timestamp] = _asPython _default_converters[java.math.BigDecimal] = _asPython _default_converters[byteArray] = bytes _default_converters[type(None)] = _nop # Adaptors can be installed after the JVM is started # JByteArray = _jpype.JArray(_jtypes.JByte) # VARCHAR.adapters[memoryview] = JByteArray _jcustomizer.getClassHints("java.sql.SQLException").registerClassBase(Error) _jinit.registerJVMInitializer(_populateTypes) jpype-1.3.0/jpype/imports.py000066400000000000000000000176461405671516700160720ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** """ JPype Imports Module -------------------- Once imported this module will place the standard Top Level Domains (TLD) into the Python scope. These TLDs are ``java``, ``com``, ``org``, ``gov``, ``mil``, ``net`` and ``edu``. Java symbols from these domains can be imported using the standard Python syntax. Import customizers are supported in Python 3.6 or greater. Forms supported: - **import [ as ]** - **import . [ as ]** - **from import [,*]** - **from import [ as ]** - **from . import [ as ]** - **from . import [ as ]** For further information please read the :doc:`imports` guide. Requires: Python 3.6 or later Example: .. code-block:: python import jpype import jpype.imports jpype.startJVM() # Import java packages as modules from java.lang import String """ import sys import _jpype from importlib.machinery import ModuleSpec as _ModuleSpec from . import _pykeywords __all__ = ["registerImportCustomizer", "registerDomain", "JImportCustomizer"] # %% Utility def _keywordUnwrap(name): if not name.endswith('_'): return name if name[:-1] in _pykeywords._KEYWORDS: return name[:-1] return name def _keywordWrap(name): if name in _pykeywords._KEYWORDS: return name + "_" return name # %% Customizer _CUSTOMIZERS = [] def _JExceptionHandler(pkg, name, ex): javaname = str(pkg) + "." + name exname = type(ex).__name__ ex._expandStacktrace() if exname == "java.lang.ExceptionInInitializerError": raise ImportError("Unable to import '%s' due to initializer error" % javaname) from ex if exname == "java.lang.UnsupportedClassVersionError": raise ImportError("Unable to import '%s' due to incorrect Java version" % javaname) from ex if exname == "java.lang.NoClassDefFoundError": missing = str(ex).replace('/', '.') raise ImportError("Unable to import '%s' due to missing dependency '%s'" % ( javaname, missing)) from ex raise ImportError("Unable to import '%s'" % javaname) from ex def registerImportCustomizer(customizer): """ Import customizers can be used to import python packages into java modules automatically. """ _CUSTOMIZERS.append(customizer) # Support hook for placing other things into the java tree class JImportCustomizer(object): """ Base class for Import customizer. Import customizers should implement canCustomize and getSpec. Example: .. code-block:: python # Site packages for each java package are stored under $DEVEL//py class SiteCustomizer(jpype.imports.JImportCustomizer): def canCustomize(self, name): if name.startswith('org.mysite') and name.endswith('.py'): return True return False def getSpec(self, name): pname = name[:-3] devel = os.environ.get('DEVEL') path = os.path.join(devel, pname,'py','__init__.py') return importlib.util.spec_from_file_location(name, path) """ def canCustomize(self, name): """ Determine if this path is to be treated differently Return: True if an alternative spec is required. """ return False def getSpec(self, name): """ Get the module spec for this module. """ raise NotImplementedError # %% Finder def unwrap(name): # Deal with Python keywords in the Java path if not '_' in name: return name return ".".join([_keywordUnwrap(i) for i in name.split('.')]) class _JImportLoader: """ (internal) Finder hook for importlib. """ def find_spec(self, name, path, target=None): # If jvm is not started then we just check against the TLDs if not _jpype.isStarted(): base = name.partition('.')[0] if not base in _JDOMAINS: return None raise ImportError("Attempt to create Java package '%s' without jvm" % name) # Check for aliases if name in _JDOMAINS: jname = _JDOMAINS[name] if not _jpype.isPackage(jname): raise ImportError("Java package '%s' not found, requested by alias '%s'" % (jname, name)) ms = _ModuleSpec(name, self) ms._jname = jname return ms # Check if it is a TLD parts = name.rpartition('.') # Use the parent module to simplify name mangling if not parts[1] and _jpype.isPackage(parts[2]): ms = _ModuleSpec(name, self) ms._jname = name return ms if not parts[1] and not _jpype.isPackage(parts[0]): return None base = sys.modules.get(parts[0], None) if not base or not isinstance(base, _jpype._JPackage): return None # Support for external modules in java tree name = unwrap(name) for customizer in _CUSTOMIZERS: if customizer.canCustomize(name): return customizer.getSpec(name) # Using isPackage eliminates need for registering tlds if not hasattr(base, parts[2]): # If the base is a Java package and it wasn't found in the # package using getAttr, then we need to emit an error # so we produce a meaningful diagnositic. try: # Use forname because it give better diagnostics cls = _jpype._java_lang_Class.forName(name, True, _jpype.JPypeClassLoader) # This code only is hit if an error was not thrown if cls.getModifiers() & 1 == 0: raise ImportError("Class `%s` is not public" % name) raise ImportError("Class `%s` was found but was not expected" % name) # Not found is acceptable except Exception as ex: raise ImportError("Failed to import '%s'" % name) from ex # Import the java module return _ModuleSpec(name, self) """ (internal) Loader hook for importlib. """ def create_module(self, spec): if spec.parent == "": return _jpype._JPackage(spec._jname) parts = spec.name.rsplit('.', 1) rc = getattr(sys.modules[spec.parent], parts[1]) # Install the handler rc._handler = _JExceptionHandler return rc def exec_module(self, fullname): pass # Install hooks into python importlib sys.meta_path.append(_JImportLoader()) # %% Domains _JDOMAINS = {} def registerDomain(mod, alias=None): """ Add a Java domain to Python as a dynamic module. This can be used to bind a Java path to a Python path. Args: mod(str): Is the Python module to bind to Java. alias(str, optional): Is the name of the Java path if different than the Python name. """ if not alias: alias = mod _JDOMAINS[mod] = alias # Preregister common top level domains registerDomain('com') registerDomain('gov') registerDomain('java') registerDomain('org') registerDomain('mil') registerDomain('edu') registerDomain('net') jpype-1.3.0/jpype/nio.py000066400000000000000000000022721405671516700151470ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import _jpype __all__ = ['convertToDirectBuffer'] def convertToDirectBuffer(obj): __doc__ = '''Efficiently convert all array.array and numpy ndarray types, string and unicode to java.nio.Buffer objects.''' memoryview_of_obj = memoryview(obj) if memoryview_of_obj.readonly: raise ValueError( "Memoryview must be writable for wrapping in a byte buffer") return _jpype.convertToDirectBuffer(memoryview_of_obj) jpype-1.3.0/jpype/pickle.py000066400000000000000000000123301405671516700156250ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** """ JPype Pickle Module -------------------- This module contains overloaded Pickler and Unpickler classes that operate on Java classes. Pickling of Java objects is restricted to classes that implement Serializable. Mixed pickle files containing both Java and Python objects are allowed. Only one copy of each Java object will appear in the pickle file even it is appears multiple times in the data structure. JPicklers and JUnpickler use Java ObjectOutputStream and ObjectInputStream to serialize objects. All of the usual Java serialization errors may be thrown. This is backed by the native cPickler implementation. Example: .. code-block:: python myobj = jpype.JClass('java.util.ArrayList')() myobj.add("test") from jpype.pickle import JPickler, JUnpickler with open("test.pic", "wb") as fd: JPickler(fd).dump(myobj) with open("test.pic", "rb") as fd: newobj = JUnpickler(fd).load() Proxies and other JPype specific module resources cannot be pickled currently. Requires: Python 3.6 or later """ from __future__ import absolute_import import _jpype import pickle from copyreg import dispatch_table # TODO: Support use of a custom classloader with the unpickler. # TODO: Use copyreg to pickle a JProxy __ALL__ = ['JPickler', 'JUnpickler'] # This must exist as a global, the real unserializer is created by the JUnpickler class JUnserializer(object): def __call__(self, *args): raise pickle.UnpicklingError("Unpickling Java requires JUnpickler") class _JDispatch(object): """Dispatch for Java classes and objects. Python does not have a good way to register a reducer that applies to many classes, thus we will substitute the usual dictionary with a class that can produce reducers as needed. """ def __init__(self, dispatch): self._encoder = _jpype.JClass('org.jpype.pickle.Encoder')() self._builder = JUnserializer() self._dispatch = dispatch # Extension dispatch table holds reduce method self._call = self.reduce # Python2 and Python3 _Pickler use get() def get(self, cls): if not issubclass(cls, (_jpype.JClass, _jpype.JObject)): return self._dispatch.get(cls) return self._call # Python3 cPickler uses __getitem__() def __getitem__(self, cls): if not issubclass(cls, (_jpype.JClass, _jpype.JObject)): return self._dispatch[cls] return self._call # For Python3 def reduce(self, obj): byte = bytes(self._encoder.pack(obj)) return (self._builder, (byte, )) class JPickler(pickle.Pickler): """Pickler overloaded to support Java objects Parameters: file: a file or other writeable object. *args: any arguments support by the native pickler. Raises: java.io.NotSerializableException: if a class is not serializable or one of its members java.io.InvalidClassException: an error occures in constructing a serialization. """ def __init__(self, file, *args, **kwargs): pickle.Pickler.__init__(self, file, *args, **kwargs) # In Python3 we need to hook into the dispatch table for extensions self.dispatch_table = _JDispatch(dispatch_table) class JUnpickler(pickle.Unpickler): """Unpickler overloaded to support Java objects Parameters: file: a file or other readable object. *args: any arguments support by the native unpickler. Raises: java.lang.ClassNotFoundException: if a serialized class is not found by the current classloader. java.io.InvalidClassException: if the serialVersionUID for the class does not match, usually as a result of a new jar version. java.io.StreamCorruptedException: if the pickle file has been altered or corrupted. """ def __init__(self, file, *args, **kwargs): self._decoder = _jpype.JClass('org.jpype.pickle.Decoder')() pickle.Unpickler.__init__(self, file, *args, **kwargs) def find_class(self, module, cls): """Specialization for Java classes. We just need to substitute the stub class for a real one which points to our decoder instance. """ if cls == "JUnserializer": decoder = self._decoder class JUnserializer(object): def __call__(self, *args): return decoder.unpack(args[0]) return JUnserializer return pickle.Unpickler.find_class(self, module, cls) jpype-1.3.0/jpype/protocol.py000066400000000000000000000122311405671516700162170ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import _jpype import datetime import decimal import sys import _jpype from . import _jclass from . import _jcustomizer # Copies of all private base types for reference _JClass = _jpype._JClass _JObject = _jpype._JObject _JException = _jpype._JException _JNumberLong = _jpype._JNumberLong _JNumberFloat = _jpype._JNumberFloat _JComparable = _jpype._JComparable _JChar = _jpype._JChar _JBoolean = _jpype._JBoolean _JArray = _jpype._JArray _JBuffer = _jpype._JBuffer if sys.version_info < (3, 8): # pragma: no cover from typing_extensions import Protocol, runtime_checkable from typing import Sequence, Mapping, Set # lgtm [py/unused-import] from typing import SupportsFloat, Callable # lgtm [py/unused-import] @runtime_checkable class SupportsIndex(Protocol): def __index__(self) -> int: ... else: # 3.8 onward from typing import Protocol, runtime_checkable from typing import SupportsIndex, SupportsFloat # lgtm [py/unused-import] from typing import Sequence, Mapping, Set, Callable # lgtm [py/unused-import] # Types we need @runtime_checkable class SupportsPath(Protocol): def __fspath__(self) -> str: ... @_jcustomizer.JConversion("java.nio.file.Path", instanceof=SupportsPath) def _JPathConvert(jcls, obj): Paths = _jpype.JClass("java.nio.file.Paths") return Paths.get(obj.__fspath__()) @_jcustomizer.JConversion("java.io.File", instanceof=SupportsPath) def _JFileConvert(jcls, obj): return jcls(obj.__fspath__()) # To be added in 1.1.x @_jcustomizer.JConversion("java.lang.Iterable", instanceof=Sequence, excludes=str) @_jcustomizer.JConversion("java.util.Collection", instanceof=Sequence, excludes=str) def _JSequenceConvert(jcls, obj): return _jclass.JClass('java.util.Arrays').asList(obj) @_jcustomizer.JConversion("java.lang.Iterable", instanceof=Set) @_jcustomizer.JConversion("java.util.Collection", instanceof=Set) def _JSetConvert(jcls, obj): # set does not satisfy PySequence_Check and collection is too broad as it # would let dict be converted, so we are going to have to convert twice # for now return _jclass.JClass('java.util.Arrays').asList(list(obj)) @_jcustomizer.JConversion("java.util.Map", instanceof=Mapping) def _JMapConvert(jcls, obj): hm = _jclass.JClass('java.util.HashMap')() for p, v in obj.items(): hm[p] = v return hm # Converters start here @_jcustomizer.JConversion("java.time.Instant", exact=datetime.datetime) def _JInstantConversion(jcls, obj): utc = obj.replace(tzinfo=datetime.timezone.utc).timestamp() sec = int(utc) nsec = int((utc - sec) * 1e9) return jcls.ofEpochSecond(sec, nsec) if sys.version_info < (3, 6): # pragma: no cover import pathlib @_jcustomizer.JConversion("java.nio.file.Path", instanceof=pathlib.PurePath) def _JPathConvert(jcls, obj): Paths = _jpype.JClass("java.nio.file.Paths") return Paths.get(str(obj)) @_jcustomizer.JConversion("java.io.File", instanceof=pathlib.PurePath) def _JFileConvert(jcls, obj): return jcls(str(obj)) # Types needed for SQL @_jcustomizer.JImplementationFor('java.sql.Date') class _JSQLDate: def _py(self): return datetime.date(self.getYear() + 1900, self.getMonth() + 1, self.getDate()) @_jcustomizer.JImplementationFor('java.sql.Time') class _JSQLTime: def _py(self): return datetime.time(self.getHours(), self.getMinutes(), self.getSeconds()) @_jcustomizer.JImplementationFor('java.sql.Timestamp') class _JDate: def _py(self): return datetime.datetime(self.getYear() + 1900, self.getMonth() + 1, self.getDate(), self.getHours(), self.getMinutes(), self.getSeconds(), self.getNanos() // 1000) @_jcustomizer.JImplementationFor('java.math.BigDecimal') class _JBigDecimal: def _py(self): return decimal.Decimal(str(self)) @_jcustomizer.JConversion("java.sql.Time", instanceof=datetime.time) def _toTime(jcls, x): return jcls(x.hour, x.minute, x.second) @_jcustomizer.JConversion("java.sql.Date", instanceof=datetime.date) def _toDate(jcls, x): return jcls(x.year - 1900, x.month - 1, x.day) @_jcustomizer.JConversion("java.sql.Timestamp", instanceof=datetime.datetime) def _toTimestamp(jcls, x): return jcls(x.year - 1900, x.month - 1, x.day, x.hour, x.minute, x.second, x.microsecond * 1000) @_jcustomizer.JConversion("java.math.BigDecimal", instanceof=decimal.Decimal) def _toBigDecimal(jcls, x): return jcls(str(x)) jpype-1.3.0/jpype/types.py000066400000000000000000000040151405671516700155230ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** """ JPype Types Module ------------------ Optional module containing only the Java types and factories used by JPype. Classes in this module include ``JArray``, ``JClass``, ``JBoolean``, ``JByte``, ``JChar``, ``JShort``, ``JInt``, ``JLong``, ``JFloat``, ``JDouble``, ``JString``, ``JObject``, and ``JException``. Example: .. code-block:: python from jpype.types import * """ # import package to get minimum types needed to use module. import _jpype from ._jclass import * from ._jobject import * from ._jarray import * from ._jexception import JException from ._jstring import * __all__ = [ 'JArray', 'JClass', 'JBoolean', 'JByte', 'JChar', 'JShort', 'JInt', 'JLong', 'JFloat', 'JDouble', 'JString', 'JObject', 'JException', ] class JBoolean(_jpype._JBoolean, internal=True): pass class JByte(_jpype._JNumberLong, internal=True): pass class JChar(_jpype._JChar, internal=True): pass class JInt(_jpype._JNumberLong, internal=True): pass class JShort(_jpype._JNumberLong, internal=True): pass class JLong(_jpype._JNumberLong, internal=True): pass class JFloat(_jpype._JNumberFloat, internal=True): pass class JDouble(_jpype._JNumberFloat, internal=True): pass _jpype.JChar = JChar jpype-1.3.0/lgtm.yml000066400000000000000000000005241405671516700143450ustar00rootroot00000000000000path_classifiers: test: - setup.py - setupext - test - examples docs: - doc extraction: cpp: index: build_command: - python3 setup.py build java: index: build_command: ant -f native/build.xml python: python_setup: version: "3" jpype-1.3.0/native/000077500000000000000000000000001405671516700141445ustar00rootroot00000000000000jpype-1.3.0/native/build.xml000066400000000000000000000020101405671516700157560ustar00rootroot00000000000000 jpype-1.3.0/native/build_coverage.xml000066400000000000000000000020611405671516700176370ustar00rootroot00000000000000 jpype-1.3.0/native/common/000077500000000000000000000000001405671516700154345ustar00rootroot00000000000000jpype-1.3.0/native/common/include/000077500000000000000000000000001405671516700170575ustar00rootroot00000000000000jpype-1.3.0/native/common/include/jp_array.h000066400000000000000000000041701405671516700210410ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef _JPARRAY_H_ #define _JPARRAY_H_ #include "jp_javaframe.h" class JPArray; class JPArrayView { public: JPArrayView(JPArray* array); JPArrayView(JPArray* array, jobject collection); ~JPArrayView(); void reference(); bool unreference(); JPContext *getContext(); public: JPArray *m_Array; void *m_Memory; Py_buffer m_Buffer; int m_RefCount; Py_ssize_t m_Shape[5]; Py_ssize_t m_Strides[5]; jboolean m_IsCopy; jboolean m_Owned; } ; /** * Class to wrap Java Class and provide low-level behavior */ class JPArray { friend class JPArrayView; public: JPArray(const JPValue& array); JPArray(JPArray* cls, jsize start, jsize stop, jsize step); virtual~ JPArray(); JPArrayClass* getClass() { return m_Class; } jsize getLength(); void setRange(jsize start, jsize length, jsize step, PyObject* val); JPPyObject getItem(jsize ndx); void setItem(jsize ndx, PyObject*); /** * Create a shallow copy of an array. * * This is used to extract a slice before calling or casting operations. * * @param frame * @param obj * @return */ jarray clone(JPJavaFrame& frame, PyObject* obj); bool isSlice() const { return m_Slice; } jarray getJava() { return m_Object.get(); } private: JPArrayClass* m_Class; JPArrayRef m_Object; jsize m_Start; jsize m_Step; jsize m_Length; bool m_Slice; } ; #endif // _JPARRAY_H_ jpype-1.3.0/native/common/include/jp_arrayclass.h000066400000000000000000000037161405671516700220740ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef _JPARRAYCLASS_H_ #define _JPARRAYCLASS_H_ /** * Class to wrap Java Class and provide low-level behavior */ class JPArrayClass : public JPClass { public: JPArrayClass(JPJavaFrame& frame, jclass cls, const string& name, JPClass* superClass, JPClass* componentType, jint modifiers); virtual~ JPArrayClass(); virtual JPPyObject convertToPythonObject(JPJavaFrame& frame, jvalue val, bool cast) override; virtual JPMatch::Type findJavaConversion(JPMatch &match) override; virtual void getConversionInfo(JPConversionInfo &info) override; JPValue newArray(JPJavaFrame& frame, int length); /** * Create a new java array containing a set of items take from * a range. * * This is used to support variable arguments. * * @param refs contains a vector of python objects. * @param start is the start of the range inclusive. * @param end is the end of the range exclusive. * @return a jvalue containing a java vector. */ jvalue convertToJavaVector(JPJavaFrame& frame, JPPyObjectVector& refs, jsize start, jsize end); virtual JPClass* getComponentType() { return m_ComponentType; } virtual bool isArray() const override { return true; } private: JPClass* m_ComponentType; } ; #endif // _JPARRAYCLASS_H_ jpype-1.3.0/native/common/include/jp_booleantype.h000077500000000000000000000063141405671516700222510ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef _JP_BOOLEAN_TYPE_H_ #define _JP_BOOLEAN_TYPE_H_ class JPBooleanType : public JPPrimitiveType { public: JPBooleanType(); virtual ~JPBooleanType(); typedef jboolean type_t; typedef jbooleanArray array_t; static inline jboolean& field(jvalue& v) { return v.z; } static inline const jboolean& field(const jvalue& v) { return v.z; } virtual JPClass* getBoxedClass(JPContext *context) const override { return context->_java_lang_Boolean; } virtual JPMatch::Type findJavaConversion(JPMatch& match) override; virtual void getConversionInfo(JPConversionInfo &info) override; virtual JPPyObject convertToPythonObject(JPJavaFrame& frame, jvalue val, bool cast) override; virtual JPValue getValueFromObject(const JPValue& obj) override; virtual JPPyObject invokeStatic(JPJavaFrame& frame, jclass, jmethodID, jvalue*) override; virtual JPPyObject invoke(JPJavaFrame& frame, jobject, jclass, jmethodID, jvalue*) override; virtual JPPyObject getStaticField(JPJavaFrame& frame, jclass c, jfieldID fid) override; virtual void setStaticField(JPJavaFrame& frame, jclass c, jfieldID fid, PyObject* val) override; virtual JPPyObject getField(JPJavaFrame& frame, jobject c, jfieldID fid) override; virtual void setField(JPJavaFrame& frame, jobject c, jfieldID fid, PyObject* val) override; virtual jarray newArrayOf(JPJavaFrame& frame, jsize size) override; virtual void setArrayRange(JPJavaFrame& frame, jarray, jsize start, jsize length, jsize step, PyObject *sequence) override; virtual JPPyObject getArrayItem(JPJavaFrame& frame, jarray, jsize ndx) override; virtual void setArrayItem(JPJavaFrame& frame, jarray, jsize ndx, PyObject* val) override; virtual char getTypeCode() override { return 'Z'; } // GCOVR_EXCL_START // These methods are required by primitive but are not used for a non // number type virtual jlong getAsLong(jvalue v) override { return field(v); } virtual jdouble getAsDouble(jvalue v) override { return field(v); } // GCOVR_EXCL_STOP virtual void getView(JPArrayView& view) override; virtual void releaseView(JPArrayView& view) override; virtual const char* getBufferFormat() override; virtual ssize_t getItemSize() override; virtual void copyElements(JPJavaFrame &frame, jarray a, jsize start, jsize len, void* memory, int offset) override; virtual PyObject *newMultiArray(JPJavaFrame &frame, JPPyBuffer &buffer, int subs, int base, jobject dims) override; } ; #endif // _JP_BOOLEAN_TYPE_H_jpype-1.3.0/native/common/include/jp_boxedtype.h000066400000000000000000000037331405671516700217320ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef _JPBOXEDCLASS_H_ #define _JPBOXEDCLASS_H_ // Boxed types have special conversion rules so that they can convert // from python primitives. This code specializes the class wrappers // to make that happen. /** * Class to wrap for Boxed types. * * These are linked to primitives. * They specialize the conversion rules to set up our table for conversion. */ class JPBoxedType : public JPClass { public: JPBoxedType(JPJavaFrame& frame, jclass clss, const string& name, JPClass* super, JPClassList& interfaces, jint modifiers, JPPrimitiveType* primitiveType); virtual ~JPBoxedType(); virtual JPMatch::Type findJavaConversion(JPMatch &match) override; virtual void getConversionInfo(JPConversionInfo &info) override; JPPrimitiveType* getPrimitive() { return m_PrimitiveType; } jobject box(JPJavaFrame &frame, jvalue v); virtual JPPyObject convertToPythonObject(JPJavaFrame& frame, jvalue val, bool cast) override; protected: JPPrimitiveType* m_PrimitiveType; public: jmethodID m_CtorID; jmethodID m_DoubleValueID; jmethodID m_FloatValueID; jmethodID m_IntValueID; jmethodID m_LongValueID; jmethodID m_BooleanValueID; jmethodID m_CharValueID; } ; #endif // _JPBOXEDCLASS_H_jpype-1.3.0/native/common/include/jp_buffer.h000066400000000000000000000024331405671516700211740ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef _JPBUFFER_H_ #define _JPBUFFER_H_ #include "jp_javaframe.h" class JPBufferType; /** * Class to wrap Java Class and provide low-level behavior */ class JPBuffer { public: JPBuffer(const JPValue& array); virtual~ JPBuffer(); JPBufferType* getClass() { return m_Class; } jobject getJava() { return m_Object.get(); } bool isReadOnly(); Py_buffer& getView(); bool isValid(); private: JPBufferType* m_Class; JPObjectRef m_Object; void *m_Address; Py_ssize_t m_Capacity; Py_buffer m_Buffer; char m_Format[3]; } ; #endif // _JPBUFFER_H_jpype-1.3.0/native/common/include/jp_buffertype.h000066400000000000000000000024611405671516700220770ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef _JPBUFFERTYPE_H_ #define _JPBUFFERTYPE_H_ /** * Class to wrap Java Class and provide low-level behavior */ class JPBufferType : public JPClass { public: JPBufferType(JPJavaFrame& frame, jclass cls, const string& name, JPClass* superClass, const JPClassList& interfaces, jint modifiers); virtual~ JPBufferType(); char* getType() { return const_cast (m_Type); } int getSize() { return m_Size; } JPPyObject convertToPythonObject(JPJavaFrame& frame, jvalue value, bool cast) override; private: const char* m_Type; int m_Size; } ; #endif // _JPBUFFERCLASS_H_jpype-1.3.0/native/common/include/jp_bytetype.h000077500000000000000000000064571405671516700216050ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef _JPBYTE_TYPE_H_ #define _JPBYTE_TYPE_H_ class JPByteType : public JPPrimitiveType { public: JPByteType(); virtual ~JPByteType() override; public: typedef jbyte type_t; typedef jbyteArray array_t; static inline jbyte& field(jvalue& v) { return v.b; } static inline const jbyte& field(const jvalue& v) { return v.b; } virtual JPClass* getBoxedClass(JPContext *context) const override { return context->_java_lang_Byte; } virtual JPMatch::Type findJavaConversion(JPMatch &match) override; virtual void getConversionInfo(JPConversionInfo &info) override; virtual JPPyObject convertToPythonObject(JPJavaFrame &frame, jvalue val, bool cast) override; virtual JPValue getValueFromObject(const JPValue& obj) override; virtual JPPyObject invokeStatic(JPJavaFrame& frame, jclass, jmethodID, jvalue*) override; virtual JPPyObject invoke(JPJavaFrame& frame, jobject, jclass, jmethodID, jvalue*) override; virtual JPPyObject getStaticField(JPJavaFrame& frame, jclass c, jfieldID fid) override; virtual void setStaticField(JPJavaFrame& frame, jclass c, jfieldID fid, PyObject* val) override; virtual JPPyObject getField(JPJavaFrame& frame, jobject c, jfieldID fid) override; virtual void setField(JPJavaFrame& frame, jobject c, jfieldID fid, PyObject* val) override; virtual jarray newArrayOf(JPJavaFrame& frame, jsize size) override; virtual void setArrayRange(JPJavaFrame& frame, jarray, jsize start, jsize length, jsize step, PyObject*) override; virtual JPPyObject getArrayItem(JPJavaFrame& frame, jarray, jsize ndx) override; virtual void setArrayItem(JPJavaFrame& frame, jarray, jsize ndx, PyObject* val) override; virtual char getTypeCode() override { return 'B'; } template static T assertRange(const T& l) { if (l < -128 || l > 127) { JP_RAISE(PyExc_OverflowError, "Cannot convert value to Java byte"); } return l; } virtual jlong getAsLong(jvalue v) override { return field(v); } virtual jdouble getAsDouble(jvalue v) override { return field(v); } virtual void getView(JPArrayView& view) override; virtual void releaseView(JPArrayView& view) override; virtual const char* getBufferFormat() override; virtual ssize_t getItemSize() override; virtual void copyElements(JPJavaFrame &frame, jarray a, jsize start, jsize len, void* memory, int offset) override; virtual PyObject *newMultiArray(JPJavaFrame &frame, JPPyBuffer &buffer, int subs, int base, jobject dims) override; private: static const jlong _Byte_Min = 127; static const jlong _Byte_Max = -128; } ; #endif // _JPBYTE_TYPE_H_jpype-1.3.0/native/common/include/jp_chartype.h000077500000000000000000000061551405671516700215520ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef _JP_CHAR_TYPE_H_ #define _JP_CHAR_TYPE_H_ class JPCharType : public JPPrimitiveType { public: JPCharType(); virtual ~JPCharType(); public: typedef jchar type_t; typedef jcharArray array_t; virtual JPValue newInstance(JPJavaFrame& frame, JPPyObjectVector& args) override; inline jchar& field(jvalue& v) { return v.c; } inline jchar field(const jvalue& v) const { return v.c; } virtual JPClass* getBoxedClass(JPContext *context) const override { return context->_java_lang_Character; } virtual JPMatch::Type findJavaConversion(JPMatch &match) override; virtual void getConversionInfo(JPConversionInfo &info) override; virtual JPPyObject convertToPythonObject(JPJavaFrame& frame, jvalue val, bool cast) override; virtual JPValue getValueFromObject(const JPValue& obj) override; virtual JPPyObject invokeStatic(JPJavaFrame& frame, jclass, jmethodID, jvalue*) override; virtual JPPyObject invoke(JPJavaFrame& frame, jobject, jclass, jmethodID, jvalue*) override; virtual JPPyObject getStaticField(JPJavaFrame& frame, jclass c, jfieldID fid) override; virtual void setStaticField(JPJavaFrame& frame, jclass c, jfieldID fid, PyObject* val) override; virtual JPPyObject getField(JPJavaFrame& frame, jobject c, jfieldID fid) override; virtual void setField(JPJavaFrame& frame, jobject c, jfieldID fid, PyObject* val) override; virtual jarray newArrayOf(JPJavaFrame& frame, jsize size) override; virtual void setArrayRange(JPJavaFrame& frame, jarray, jsize start, jsize length, jsize step, PyObject*) override; virtual JPPyObject getArrayItem(JPJavaFrame& frame, jarray, jsize ndx) override; virtual void setArrayItem(JPJavaFrame& frame, jarray, jsize ndx, PyObject* val) override; virtual char getTypeCode() override { return 'C'; } virtual jlong getAsLong(jvalue v) override { return field(v); } virtual jdouble getAsDouble(jvalue v) override { return field(v); } virtual void getView(JPArrayView& view) override; virtual void releaseView(JPArrayView& view) override; virtual const char* getBufferFormat() override; virtual ssize_t getItemSize() override; virtual void copyElements(JPJavaFrame &frame, jarray a, jsize start, jsize len, void* memory, int offset) override; virtual PyObject *newMultiArray(JPJavaFrame &frame, JPPyBuffer &buffer, int subs, int base, jobject dims) override; } ; #endif // _JP-CHAR_TYPE_H_jpype-1.3.0/native/common/include/jp_class.h000066400000000000000000000125471405671516700210370ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef _JP_CLASS_H_ #define _JP_CLASS_H_ #include "jp_modifier.h" class JPClass : public JPResource { public: // Special entry point for JVM independent entities JPClass(const string& name, jint modifiers); JPClass(JPJavaFrame& context, jclass clss, const string& name, JPClass* super, const JPClassList& interfaces, jint modifiers); virtual ~JPClass(); void setHost(PyObject* host); PyTypeObject* getHost() { return (PyTypeObject*) m_Host.get(); } void setHints(PyObject* host); PyObject* getHints() { return m_Hints.get(); } public: void ensureMembers(JPJavaFrame& frame); jclass getJavaClass() const; void assignMembers(JPMethodDispatch* ctor, JPMethodDispatchList& methods, JPFieldList& fields); string toString() const; string getCanonicalName() const { return m_CanonicalName; } string getName() const; bool isAbstract() const { return JPModifier::isAbstract(m_Modifiers); } bool isFinal() const { return JPModifier::isFinal(m_Modifiers); } bool isThrowable() const { return JPModifier::isThrowable(m_Modifiers); } bool isInterface() const { return JPModifier::isInterface(m_Modifiers); } virtual bool isArray() const { return false; } jlong getModifiers() { return m_Modifiers; } virtual bool isPrimitive() const { return false; } virtual bool isPrimitiveArray() const { return JPModifier::isPrimitiveArray(m_Modifiers); } JPMethodDispatch* getCtor() { return m_Constructors; } const JPMethodDispatchList& getMethods() { return m_Methods; } const JPFieldList& getFields() { return m_Fields; } /** * Determine if a Python object will convert to this java type. * * This is used to determine which overload is the best match. * * @param pyobj is the Python object. * @return the quality of the match */ virtual JPMatch::Type findJavaConversion(JPMatch& match); virtual void getConversionInfo(JPConversionInfo &info); /** Create a new Python object to wrap a Java value. * * Some conversion convert to a Python type such as Java boolean and char. * Null pointers match to Python None. Objects convert automatically to * the most derived type. To disable this behavior the cast option can be * specified. * * @param cast force the wrapper to be the defined type. * @return a new Python object. */ virtual JPPyObject convertToPythonObject(JPJavaFrame& frame, jvalue val, bool cast); /** * Get the Java value representing as an object. * * This will unbox if the type is a primitive. * * @return a java value with class. */ virtual JPValue getValueFromObject(const JPValue& obj); /** * Call a static method that returns this type of object. */ virtual JPPyObject invokeStatic(JPJavaFrame& frame, jclass, jmethodID, jvalue*); /** * Call a method that returns this type of object. */ virtual JPPyObject invoke(JPJavaFrame& frame, jobject, jclass clazz, jmethodID, jvalue*); /** * Get a static field that returns this type. * * @param frame is the frame to hold the local reference. * @param cls is the class holding the static field. * @param fid is the field id. * @return */ virtual JPPyObject getStaticField(JPJavaFrame& frame, jclass cls, jfieldID fid); virtual void setStaticField(JPJavaFrame& frame, jclass cls, jfieldID fid, PyObject* val); virtual JPPyObject getField(JPJavaFrame& frame, jobject obj, jfieldID fid); virtual void setField(JPJavaFrame& frame, jobject obj, jfieldID fid, PyObject* val); JPClass* newArrayType(JPJavaFrame &frame, long d); virtual jarray newArrayOf(JPJavaFrame& frame, jsize size); virtual void setArrayRange(JPJavaFrame& frame, jarray, jsize start, jsize length, jsize step, PyObject* vals); virtual JPPyObject getArrayItem(JPJavaFrame& frame, jarray, jsize ndx); virtual void setArrayItem(JPJavaFrame& frame, jarray, jsize ndx, PyObject* val); /** * Expose IsAssignableFrom to python. */ virtual bool isAssignableFrom(JPJavaFrame& frame, JPClass* o); // Object properties JPClass* getSuperClass() { return m_SuperClass; } virtual JPValue newInstance(JPJavaFrame& frame, JPPyObjectVector& args); const JPClassList& getInterfaces() { return m_Interfaces; } JPContext* getContext() const; protected: JPContext* m_Context; JPClassRef m_Class; JPClass* m_SuperClass; JPClassList m_Interfaces; JPMethodDispatch* m_Constructors; JPMethodDispatchList m_Methods; JPFieldList m_Fields; string m_CanonicalName; jint m_Modifiers; JPPyObject m_Host; JPPyObject m_Hints; } ; #endif // _JPPOBJECTTYPE_H_jpype-1.3.0/native/common/include/jp_classhints.h000066400000000000000000000072471405671516700221060ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef JP_CLASSHINTS_H #define JP_CLASSHINTS_H class JPConversion { public: virtual ~JPConversion(); virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) = 0; virtual void getInfo(JPClass *cls, JPConversionInfo &info) = 0; virtual jvalue convert(JPMatch &match) = 0; } ; class JPIndexConversion : public JPConversion { public: virtual void getInfo(JPClass *cls, JPConversionInfo &info) override; } ; class JPNumberConversion : public JPIndexConversion { public: virtual void getInfo(JPClass *cls, JPConversionInfo &info) override; } ; class JPConversionJavaValue : public JPConversion { public: virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) override; virtual void getInfo(JPClass *cls, JPConversionInfo &info) override; virtual jvalue convert(JPMatch &match) override; } ; class JPClassHints { public: JPClassHints(); ~JPClassHints(); /** Get the conversion of this type. * * Searches the list for a conversion. The first conversion better than * explicit is returned immediately. * * @returns the quality of the match */ JPMatch::Type getConversion(JPMatch& match, JPClass *cls); /** * Add a conversion based on a specified attribute. * * If the attribute is found in in the object, it is assumed to be a match. * This is for "duck type" conversions. The Python routine must return * something that holds a __javavalue__ which will be used as the converted * object. * * @param attribute is the attribute to search for. * @param method is a Python routine to call to complete the conversion * process. */ void addAttributeConversion(const string& attribute, PyObject* method); /** * Add a type conversion based on the Python type. * * The Python routine must return something that holds a __javavalue__ * which will be used as the converted object. * * @param type is a Python type object * @param method is a Python routine to call to complete the conversion * process. * @param exact require the type to be an exact match. */ void addTypeConversion(PyObject* type, PyObject* method, bool exact); void excludeConversion(PyObject* type); void getInfo(JPClass *cls, JPConversionInfo &info); private: std::list conversions; } ; extern JPConversion *hintsConversion; extern JPConversion *charArrayConversion; extern JPConversion *byteArrayConversion; extern JPConversion *bufferConversion; extern JPConversion *sequenceConversion; extern JPConversion *nullConversion; extern JPConversion *classConversion; extern JPConversion *objectConversion; extern JPConversion *javaObjectAnyConversion; extern JPConversion *javaNumberAnyConversion; extern JPConversion *javaValueConversion; extern JPConversion *stringConversion; extern JPConversion *boxConversion; extern JPConversion *boxBooleanConversion; extern JPConversion *boxLongConversion; extern JPConversion *boxDoubleConversion; extern JPConversion *unboxConversion; extern JPConversion *proxyConversion; #endif /* JP_CLASSHINTS_H */jpype-1.3.0/native/common/include/jp_classloader.h000066400000000000000000000032671405671516700222250ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef _JPCLASSLOADER_H_ #define _JPCLASSLOADER_H_ #include "jp_class.h" /** * The class loader is reponsible for loading classes within JPype. * * Depending on the settings it may either use an internal boot loader * to get the jar from within the _jpype module, or it may use the * system class loader. */ class JPClassLoader { public: /** Initialize the class loader. */ JPClassLoader(JPJavaFrame& frame); /** Load a class by name from the jpype.jar. * * String is specified as a Java binary name. * https://docs.oracle.com/javase/7/docs/api/java/lang/ClassLoader.html#name * * @returns the class loaded * @throws RuntimeException if the class is not found. */ jclass findClass(JPJavaFrame& frame, const string& name); // Classloader for Proxy jobject getBootLoader(); private: JPContext* m_Context; JPClassRef m_ClassClass; JPObjectRef m_SystemClassLoader; JPObjectRef m_BootLoader; jmethodID m_ForNameID; } ; #endif // _JPCLASSLOADER_H_jpype-1.3.0/native/common/include/jp_classtype.h000066400000000000000000000025671405671516700217420ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef _JPCLASSTYPE_H_ #define _JPCLASSTYPE_H_ /** * Wrapper for Class * * Class wrappers need to be able to cast to this type, * thus we need a specialized version. * This class should not be used outside of * the JPTypeManager. */ class JPClassType : public JPClass { public: JPClassType(JPJavaFrame& frame, jclass clss, const string& name, JPClass* super, JPClassList& interfaces, jint modifiers); virtual~ JPClassType(); public: // JPClass implementation virtual JPMatch::Type findJavaConversion(JPMatch &match) override; void getConversionInfo(JPConversionInfo &info) override; } ; #endif // _JPCLASSTYPE_H_jpype-1.3.0/native/common/include/jp_context.h000066400000000000000000000202141405671516700214040ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef JP_CONTEXT_H #define JP_CONTEXT_H #include #include /** JPClass is a bit heavy when we just need to hold a * class reference. It causes issues during bootstrap. Thus we * need a lightweight reference to a jclass. */ template class JPRef { private: JPContext* m_Context; jref m_Ref; public: JPRef() { m_Context = 0; m_Ref = 0; } JPRef(JPContext* context, jref obj) { m_Context = context; m_Ref = 0; if (context == 0) return; JPJavaFrame frame = JPJavaFrame::outer(m_Context); m_Ref = (jref) frame.NewGlobalRef((jobject) obj); } JPRef(JPJavaFrame& frame, jref obj) { m_Context = frame.getContext(); m_Ref = 0; m_Ref = (jref) frame.NewGlobalRef((jobject) obj); } JPRef(const JPRef& other); ~JPRef(); JPRef& operator=(const JPRef& other); jref get() const { return m_Ref; } } ; typedef JPRef JPClassRef; typedef JPRef JPObjectRef; typedef JPRef JPArrayRef; typedef JPRef JPThrowableRef; class JPStackInfo; class JPGarbageCollection; void assertJVMRunning(JPContext* context, const JPStackInfo& info); int hasInterrupt(); /** * A Context encapsulates the Java virtual machine, the Java classes required * to function, and the JPype services created for that machine. * * Frames, Environments and Contexts are different concepts. * - Java context is shared with all objects that exist in a virtual machine. * - Java environment exists for each thread for each machine. * - Java frames exist in the stack holding the local variables that * method. * Frames and Environments should never be held longer than the duration of * a method. * * The members in the Context are broken into * - JVM control functions * - JPype services * - Java functions * - Java type resources * * There are two critical phases in the context lifespan where things * are most likely to go wrong. During JVM startup, many vital functions are * not yet fully configured and thus an exception issued during that period * can lead to using a resource that is not yet configured. * * Second shutdown is a vital period. If the user calls shutdown from within * a callback in which there are still JPype context elements on the call * stack, it can lead to a crash. * * After shutdown, the JVM is set to NULL and all actions should assert that * it is running and thus fail. Aside from the context and the services, all * other JPype C++ resources are owned by Java. Java will delete them as needed. * The context itself belongs to Python. */ class JPContext { public: friend class JPJavaFrame; friend class JPypeException; friend class JPClass; JPContext(); virtual ~JPContext(); // JVM control functions bool isRunning(); void startJVM(const string& vmPath, const StringVector& args, bool ignoreUnrecognized, bool convertStrings, bool interrupt); void attachJVM(JNIEnv* env); void initializeResources(JNIEnv* env, bool interrupt); void shutdownJVM(bool destroyJVM, bool freeJVM); void attachCurrentThread(); void attachCurrentThreadAsDaemon(); bool isThreadAttached(); void detachCurrentThread(); JNIEnv* getEnv(); JavaVM* getJavaVM() { return m_JavaVM; } jobject getJavaContext() { return m_JavaContext.get(); } /** Release a global reference checking for shutdown. * * This should be used in any calls to release resources from a destructor. * It cannot fail even if the JVM is no longer operating. */ void ReleaseGlobalRef(jobject obj); // JPype services JPTypeManager* getTypeManager() { return m_TypeManager; } JPClassLoader* getClassLoader() { return m_ClassLoader; } bool getConvertStrings() const { return m_ConvertStrings; } // Java type resources JPPrimitiveType* _void; JPPrimitiveType* _boolean; JPPrimitiveType* _byte; JPPrimitiveType* _char; JPPrimitiveType* _short; JPPrimitiveType* _int; JPPrimitiveType* _long; JPPrimitiveType* _float; JPPrimitiveType* _double; JPBoxedType* _java_lang_Void; JPBoxedType* _java_lang_Boolean; JPBoxedType* _java_lang_Byte; JPBoxedType* _java_lang_Character; JPBoxedType* _java_lang_Short; JPBoxedType* _java_lang_Integer; JPBoxedType* _java_lang_Long; JPBoxedType* _java_lang_Float; JPBoxedType* _java_lang_Double; JPClass* _java_lang_Object; JPClass* _java_lang_Class; JPClass* _java_lang_reflect_Field; JPClass* _java_lang_reflect_Method; JPClass* _java_lang_Throwable; JPStringType* _java_lang_String; JPClass* _java_nio_ByteBuffer; private: void loadEntryPoints(const string& path); jint(JNICALL * CreateJVM_Method)(JavaVM **pvm, void **penv, void *args); jint(JNICALL * GetCreatedJVMs_Method)(JavaVM **pvm, jsize size, jsize * nVms); private: JPContext(const JPContext& orig); JavaVM *m_JavaVM; // Java half JPObjectRef m_JavaContext; // Services JPTypeManager *m_TypeManager; JPClassLoader *m_ClassLoader; public: JPClassRef m_ContextClass; JPClassRef m_RuntimeException; JPClassRef m_NoSuchMethodError; private: JPClassRef m_Array; // Java Functions jmethodID m_Object_ToStringID; jmethodID m_Object_EqualsID; jmethodID m_Object_HashCodeID; jmethodID m_CallMethodID; jmethodID m_Class_GetNameID; jmethodID m_Context_collectRectangularID; jmethodID m_Context_assembleID; jmethodID m_String_ToCharArrayID; jmethodID m_Context_CreateExceptionID; jmethodID m_Context_GetExcClassID; jmethodID m_Context_GetExcValueID; jmethodID m_Context_ClearInterruptID; jmethodID m_CompareToID; jmethodID m_Buffer_IsReadOnlyID; jmethodID m_Context_OrderID; jmethodID m_Object_GetClassID; jmethodID m_Array_NewInstanceID; jmethodID m_Throwable_GetCauseID; jmethodID m_Throwable_GetMessageID; jmethodID m_Context_GetFunctionalID; friend class JPProxy; JPClassRef m_ProxyClass; jmethodID m_Proxy_NewID; jmethodID m_Proxy_NewInstanceID; jmethodID m_Context_IsPackageID; jmethodID m_Context_GetPackageID; jmethodID m_Package_GetObjectID; jmethodID m_Package_GetContentsID; jmethodID m_Context_NewWrapperID; public: jmethodID m_Context_GetStackFrameID; void onShutdown(); private: bool m_Running; bool m_ConvertStrings; bool m_Embedded; public: JPGarbageCollection *m_GC; // This will gather C++ resources to clean up after shutdown. std::list m_Resources; } ; extern void JPRef_failed(); // GCOVR_EXCL_START // Not currently used template JPRef::JPRef(const JPRef& other) { m_Context = other.m_Context; if (m_Context != NULL) { JPJavaFrame frame = JPJavaFrame::external(m_Context, m_Context->getEnv()); m_Ref = (jref) frame.NewGlobalRef((jobject) other.m_Ref); } else { JPRef_failed(); } } // GCOVR_EXCL_STOP template JPRef::~JPRef() { if (m_Ref != 0 && m_Context != 0) { m_Context->ReleaseGlobalRef((jobject) m_Ref); } } template JPRef& JPRef::operator=(const JPRef& other) { if (other.m_Ref == m_Ref) return *this; // m_Context may or may not be set up here, so we need to use a // different frame for unreferencing and referencing if (m_Context != 0 && m_Ref != 0) { // GCOVR_EXCL_START // This code is not currently used. JPJavaFrame frame = JPJavaFrame::external(m_Context, m_Context->getEnv()); if (m_Ref != 0) frame.DeleteGlobalRef((jobject) m_Ref); } // GCOVR_EXCL_STOP m_Context = other.m_Context; m_Ref = other.m_Ref; if (m_Context != 0 && m_Ref != 0) { JPJavaFrame frame = JPJavaFrame::external(m_Context, m_Context->getEnv()); m_Ref = (jref) frame.NewGlobalRef((jobject) m_Ref); } return *this; } #endif /* JP_CONTEXT_H */ jpype-1.3.0/native/common/include/jp_doubletype.h000077500000000000000000000063141405671516700221040ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef _JP_DOUBLE_TYPE_H_ #define _JP_DOUBLE_TYPE_H_ class JPDoubleType : public JPPrimitiveType { public: JPDoubleType(); virtual ~JPDoubleType(); public: typedef jdouble type_t; typedef jdoubleArray array_t; static inline jdouble& field(jvalue& v) { return v.d; } static inline const jdouble& field(const jvalue& v) { return v.d; } virtual JPClass* getBoxedClass(JPContext *context) const override { return context->_java_lang_Double; } virtual JPMatch::Type findJavaConversion(JPMatch &match) override; virtual void getConversionInfo(JPConversionInfo &info) override; virtual JPPyObject convertToPythonObject(JPJavaFrame &frame, jvalue val, bool cast) override; virtual JPValue getValueFromObject(const JPValue& obj) override; virtual JPPyObject invokeStatic(JPJavaFrame &frame, jclass, jmethodID, jvalue*) override; virtual JPPyObject invoke(JPJavaFrame &frame, jobject, jclass, jmethodID, jvalue*) override; virtual JPPyObject getStaticField(JPJavaFrame& frame, jclass c, jfieldID fid) override; virtual void setStaticField(JPJavaFrame& frame, jclass c, jfieldID fid, PyObject* val) override; virtual JPPyObject getField(JPJavaFrame& frame, jobject c, jfieldID fid) override; virtual void setField(JPJavaFrame& frame, jobject c, jfieldID fid, PyObject* val) override; virtual jarray newArrayOf(JPJavaFrame& frame, jsize size) override; virtual void setArrayRange(JPJavaFrame& frame, jarray, jsize start, jsize length, jsize step, PyObject*) override; virtual JPPyObject getArrayItem(JPJavaFrame& frame, jarray, jsize ndx) override; virtual void setArrayItem(JPJavaFrame& frame, jarray, jsize ndx, PyObject* val) override; virtual char getTypeCode() override { return 'D'; } // GCOV_EXCL_START // These are required for primitives, but converters for do not currently // use them. virtual jlong getAsLong(jvalue v) override { return (jlong) field(v); } virtual jdouble getAsDouble(jvalue v) override { return (jdouble) field(v); } // GCOV_EXCL_STOP virtual void getView(JPArrayView& view) override; virtual void releaseView(JPArrayView& view) override; virtual const char* getBufferFormat() override; virtual ssize_t getItemSize() override; virtual void copyElements(JPJavaFrame &frame, jarray a, jsize start, jsize len, void* memory, int offset) override; virtual PyObject *newMultiArray(JPJavaFrame &frame, JPPyBuffer& view, int subs, int base, jobject dims) override; } ; #endif // _JP_DOUBLE_TYPE_H_jpype-1.3.0/native/common/include/jp_encoding.h000066400000000000000000000036461405671516700215200ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef _JP_ENCODING_H_ #define _JP_ENCODING_H_ #include #include #include class JPEncoding { public: JPEncoding() { } virtual ~JPEncoding(); /** Store a code point in an outgoing buffer. */ virtual void encode(std::ostream& out, unsigned int codePoint) const = 0; /** Retrieve a coding point from an incoming buffer. */ virtual unsigned int fetch(std::istream& is) const = 0; } ; class JPEncodingUTF8 : public JPEncoding { public: /** Store a code point in an outgoing buffer. */ void encode(std::ostream& out, unsigned int codePoint) const override; /** Retrieve a coding point from an incoming buffer. */ unsigned int fetch(std::istream& is) const override; } ; class JPEncodingJavaUTF8 : public JPEncoding { public: /** Store a code point in an outgoing buffer. */ void encode(std::ostream& out, unsigned int codePoint) const override; /** Retrieve a coding point from an incoming buffer. * returns the next coding point or -1 on invalid coding. */ unsigned int fetch(std::istream& is) const override; } ; std::string transcribe(const char* in, size_t len, const JPEncoding& sourceEncoding, const JPEncoding& targetEncoding); #endif // _JP_ENCODING_H_jpype-1.3.0/native/common/include/jp_exception.h000066400000000000000000000110661405671516700217230ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef _JP_EXCEPTION_H_ #define _JP_EXCEPTION_H_ /* All exception are passed as JPypeException. The type of the exception * is specified at creation. Exceptions may be of type * - _java_error - exception generated from within java. * - _python_error - excepction generated from within python. * - _runtime_error - Failure that will issue a runtime error in python and java. * - _type_error - Failure that will issue a type error in python. * * We must throw the correct exception so that it can properly be handled * when returning back to the native code. * * If we are returning to python, and it is a * - _python_error, then we assume that a python exception has already been * placed in the python virtual machine. * - _java_error, then we will covert it to a python object with the correct * object type. * - otherwise, then we will convert it to the requested python error. * * If we are returning to java, and it is a * - _java_error, they we assume there is already an Java exception queue * in the virtual machine. * - otherwise convert to a RuntimeException. * */ #ifndef __FUNCTION_NAME__ #ifdef WIN32 //WINDOWS #define __FUNCTION_NAME__ __FUNCTION__ #else //*NIX #define __FUNCTION_NAME__ __func__ #endif #endif /** * This is the type of the exception to issue. */ namespace JPError { extern int _java_error; extern int _python_error; extern int _python_exc; extern int _os_error_unix; extern int _os_error_windows; extern int _method_not_found; } // Create a stackinfo for a particular location in the code that can then // be passed to the handler routine for auditing. #define JP_STACKINFO() JPStackInfo(__FUNCTION_NAME__, __FILE__, __LINE__) // Macro to use when hardening code // Most of these will be removed after core is debugged, but // a few are necessary to handle off normal conditions. #define ASSERT_NOT_NULL(X) {if (X==NULL) { JP_RAISE(PyExc_RuntimeError, "Null Pointer Exception");} } // Macro to add stack trace info when multiple paths lead to the same trouble spot #define JP_CATCH catch (JPypeException& ex) { ex.from(JP_STACKINFO()); throw; } /** Structure to pass around the location within a C++ source file. */ class JPStackInfo { const char* function_; const char* file_; int line_; public: JPStackInfo(const char* function, const char* file, int line) : function_(function), file_(file), line_(line) { } const char* getFunction() const { return function_; } const char* getFile() const { return file_; } int getLine() const { return line_; } } ; typedef vector JPStackTrace; typedef union { int i; void* l; } JPErrorUnion; /** * Exception issued by JPype to indicate an internal problem. * * This is primarily focused on transferring exception handling * to Python as the majority of errors are reported there. * */ class JPypeException { public: JPypeException(JPJavaFrame &frame, jthrowable, const JPStackInfo& stackInfo); JPypeException(int type, void* error, const JPStackInfo& stackInfo); JPypeException(int type, void* error, const string& msn, const JPStackInfo& stackInfo); JPypeException(int type, const string& msn, int error, const JPStackInfo& stackInfo); JPypeException(const JPypeException& ex); JPypeException& operator = (const JPypeException& ex); ~JPypeException(); void from(const JPStackInfo& info); string getMessage(); void convertJavaToPython(); void convertPythonToJava(JPContext* context); /** Transfer handling of this exception to python. * * This should appear in the catch block whenever we return to python. * */ void toPython(); /** Transfer handling of this exception to java. */ void toJava(JPContext* context); int getExceptionType() { return m_Type; } private: JPContext* m_Context; int m_Type; JPErrorUnion m_Error; JPStackTrace m_Trace; string m_Message; JPThrowableRef m_Throwable; } ; #endifjpype-1.3.0/native/common/include/jp_field.h000066400000000000000000000035601405671516700210100ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef _JPFIELD_H_ #define _JPFIELD_H_ /** * Field object */ class JPField { public: /** * Create a new field based on class and java.lang.Field object */ JPField(JPJavaFrame& frame, JPClass *cls, const string& name, jobject field, jfieldID fid, JPClass *fieldType, jint modifiers); /** * destructor */ virtual ~JPField(); jobject getJavaObject() { return this->m_Field.get(); } JPContext* getContext() { return m_Class->getContext(); } const string& getName() const { return m_Name; } JPPyObject getStaticField(); void setStaticField(PyObject *pyobj); JPPyObject getField(jobject inst); void setField(jobject inst, PyObject *pyobj); bool isFinal() const { return JPModifier::isFinal(m_Modifiers); } bool isStatic() const { return JPModifier::isStatic(m_Modifiers); } JPClass *getClass() const { return m_Class; } private: JPField(const JPField&); JPField& operator=(const JPField&) ; string m_Name; JPClass* m_Class; JPObjectRef m_Field; jfieldID m_FieldID; JPClass* m_Type; jint m_Modifiers; } ; #endif // _JPFIELD_H_jpype-1.3.0/native/common/include/jp_floattype.h000077500000000000000000000062521405671516700217400ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef _JP_FLOAT_TYPE_H_ #define _JP_FLOAT_TYPE_H_ class JPFloatType : public JPPrimitiveType { public: JPFloatType(); virtual ~JPFloatType(); public: typedef jfloat type_t; typedef jfloatArray array_t; static inline jfloat& field(jvalue& v) { return v.f; } static inline const jfloat& field(const jvalue& v) { return v.f; } virtual JPClass* getBoxedClass(JPContext *context) const override { return context->_java_lang_Float; } virtual JPMatch::Type findJavaConversion(JPMatch &match) override; virtual void getConversionInfo(JPConversionInfo &info) override; virtual JPPyObject convertToPythonObject(JPJavaFrame &frame, jvalue val, bool cast) override; virtual JPValue getValueFromObject(const JPValue& obj) override; virtual JPPyObject invokeStatic(JPJavaFrame& frame, jclass, jmethodID, jvalue*) override; virtual JPPyObject invoke(JPJavaFrame& frame, jobject, jclass, jmethodID, jvalue*) override; virtual JPPyObject getStaticField(JPJavaFrame& frame, jclass c, jfieldID fid) override; virtual void setStaticField(JPJavaFrame& frame, jclass c, jfieldID fid, PyObject* val) override; virtual JPPyObject getField(JPJavaFrame& frame, jobject c, jfieldID fid) override; virtual void setField(JPJavaFrame& frame, jobject c, jfieldID fid, PyObject* val) override; virtual jarray newArrayOf(JPJavaFrame& frame, jsize size) override; virtual void setArrayRange(JPJavaFrame& frame, jarray, jsize start, jsize length, jsize step, PyObject* sequence) override; virtual JPPyObject getArrayItem(JPJavaFrame& frame, jarray, jsize ndx) override; virtual void setArrayItem(JPJavaFrame& frame, jarray, jsize ndx, PyObject* val) override; virtual char getTypeCode() override { return 'F'; } // GCOVR_EXCL_START // This is required, but is not currently used. virtual jlong getAsLong(jvalue v) override { return (jlong) field(v); } // GCOVR_EXCL_STOP virtual jdouble getAsDouble(jvalue v) override { return (jdouble) field(v); } virtual void getView(JPArrayView& view) override; virtual void releaseView(JPArrayView& view) override; virtual const char* getBufferFormat() override; virtual ssize_t getItemSize() override; virtual void copyElements(JPJavaFrame &frame, jarray a, jsize start, jsize len, void* memory, int offset) override; virtual PyObject *newMultiArray(JPJavaFrame &frame, JPPyBuffer &buffer, int subs, int base, jobject dims) override; } ; #endif // _JP_FLOAT_TYPE_H_jpype-1.3.0/native/common/include/jp_functional.h000066400000000000000000000023331405671516700220640ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef JP_FUNCTIONAL_H #define JP_FUNCTIONAL_H class JPFunctional : public JPClass { public: JPFunctional(JPJavaFrame& frame, jclass clss, const string& name, JPClass* super, JPClassList& interfaces, jint modifiers); virtual ~JPFunctional(); virtual JPMatch::Type findJavaConversion(JPMatch &match) override; virtual void getConversionInfo(JPConversionInfo &info) override; string getMethod() { return m_Method; } protected: string m_Method; } ; #endif /* JP_FUNCTIONAL_H */jpype-1.3.0/native/common/include/jp_gc.h000066400000000000000000000031321405671516700203110ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef JP_GC_H #define JP_GC_H struct JPGCStats { long long python_rss; long long java_rss; long long current_rss; long long max_rss; long long min_rss; long long python_triggered; } ; class JPGarbageCollection { public: JPGarbageCollection(JPContext *context); void init(JPJavaFrame& frame); void shutdown(); void triggered(); /** * Called when Python starts it Garbage collector */ void onStart(); /** * Called when Python finishes it Garbage collector */ void onEnd(); void getStats(JPGCStats& stats); private: JPContext *m_Context; bool running; bool in_python_gc; bool java_triggered; PyObject *python_gc; jclass _SystemClass; jmethodID _gcMethodID; size_t last_python; size_t last_java; size_t low_water; size_t high_water; size_t limit; size_t last; int java_count; int python_count; int python_triggered; } ; #endif /* JP_GC_H */jpype-1.3.0/native/common/include/jp_inttype.h000077500000000000000000000064031405671516700214230ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef _JP_INT_TYPE_H_ #define _JP_INT_TYPE_H_ class JPIntType : public JPPrimitiveType { public: JPIntType(); virtual ~JPIntType(); public: typedef jint type_t; typedef jintArray array_t; static inline jint& field(jvalue& v) { return v.i; } static inline const jint& field(const jvalue& v) { return v.i; } virtual JPClass* getBoxedClass(JPContext *context) const override { return context->_java_lang_Integer; } virtual JPMatch::Type findJavaConversion(JPMatch& match) override; void getConversionInfo(JPConversionInfo &info) override; virtual JPPyObject convertToPythonObject(JPJavaFrame& frame, jvalue val, bool cast) override; virtual JPValue getValueFromObject(const JPValue& obj) override; virtual JPPyObject invokeStatic(JPJavaFrame& frame, jclass, jmethodID, jvalue*) override; virtual JPPyObject invoke(JPJavaFrame& frame, jobject, jclass, jmethodID, jvalue*) override; virtual JPPyObject getStaticField(JPJavaFrame& frame, jclass c, jfieldID fid) override; virtual void setStaticField(JPJavaFrame& frame, jclass c, jfieldID fid, PyObject* val) override; virtual JPPyObject getField(JPJavaFrame& frame, jobject c, jfieldID fid) override; virtual void setField(JPJavaFrame& frame, jobject c, jfieldID fid, PyObject* val) override; virtual jarray newArrayOf(JPJavaFrame& frame, jsize size) override; virtual void setArrayRange(JPJavaFrame& frame, jarray, jsize start, jsize length, jsize step, PyObject* sequence) override; virtual JPPyObject getArrayItem(JPJavaFrame& frame, jarray, jsize ndx) override; virtual void setArrayItem(JPJavaFrame& frame, jarray, jsize ndx, PyObject* val) override; virtual char getTypeCode() override { return 'I'; } virtual jlong getAsLong(jvalue v) override // GCOVR_EXCL_LINE { return field(v); // GCOVR_EXCL_LINE } virtual jdouble getAsDouble(jvalue v) override { return field(v); } static jlong assertRange(const jlong& l) { if (l < -2147483648ll || l > 2147483647ll) { JP_RAISE(PyExc_OverflowError, "Cannot convert value to Java int"); } return l; } virtual void getView(JPArrayView& view) override; virtual void releaseView(JPArrayView& view) override; virtual const char* getBufferFormat() override; virtual ssize_t getItemSize() override; virtual void copyElements(JPJavaFrame &frame, jarray a, jsize start, jsize len, void* memory, int offset) override; virtual PyObject *newMultiArray(JPJavaFrame &frame, JPPyBuffer &buffer, int subs, int base, jobject dims) override; } ; #endif // _JP_INT_TYPE_H_jpype-1.3.0/native/common/include/jp_javaframe.h000066400000000000000000000362001405671516700216560ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef _JP_JAVA_FRAME_H_ #define _JP_JAVA_FRAME_H_ /** A Java Frame represents a memory managed scope in which * java objects can be manipulated. * * Any resources created within a Java frame will be automatically * deallocated at when the frame falls out of scope unless captured * by a global reference. * * This should be used around all entry points from python that * call java code. Failure may lead to local references not being * released. Methods will large numbers of local references * should allocate a local frame. At most one local reference * from a local frame can be kept. Addition must use global referencing. * * JavaFrames are created to hold a certain number of items in * scope at time. They will grow automatically if more items are * created, but this has overhead. For most cases the default * will be fine. However, when working with an array in which * the number of items in scope can be known in advance, it is * good to size the frame appropriately. * * A JavaFrame should not be used in a destructor as it can * throw. The most common use of JavaFrame is to delete a * global reference. See the ReleaseGlobalReference for * this purpose. */ static const int LOCAL_FRAME_DEFAULT = 8; class JPContext; class JPJavaFrame { JPContext* m_Context; JNIEnv* m_Env; bool m_Popped; bool m_Outer; private: JPJavaFrame(JPContext* context, JNIEnv* env, int size, bool outer); public: /** Create a new JavaFrame when called from Python. * * This method will automatically attach the thread * if it is not already attached. * * @param size determines how many objects can be * created in this scope without additional overhead. * * @throws JPypeException if the jpype cannot * acquire an env handle to work with jvm. */ static JPJavaFrame outer(JPContext* context, int size = LOCAL_FRAME_DEFAULT) { return JPJavaFrame(context, NULL, size, true); } /** Create a new JavaFrame when called internal when * there is an existing frame. * * @param size determines how many objects can be * created in this scope without additional overhead. * * @throws JPypeException if the jpype cannot * acquire an env handle to work with jvm. */ static JPJavaFrame inner(JPContext* context, int size = LOCAL_FRAME_DEFAULT) { return JPJavaFrame(context, NULL, size, false); } /** Create a new JavaFrame when called from Java. * * The thread was attached by definition. * * @param size determines how many objects can be * created in this scope without additional overhead. * * @throws JPypeException if the jpype cannot * acquire an env handle to work with jvm. */ static JPJavaFrame external(JPContext* context, JNIEnv* env, int size = LOCAL_FRAME_DEFAULT) { return JPJavaFrame(context, env, size, false); } JPJavaFrame(const JPJavaFrame& frame); /** Exit the local scope and clean up all java * objects. * * Only the one local object passed to outer scope * by the keep method will be kept alive. */ ~JPJavaFrame(); void check(); /** Exit the local frame and keep a local reference to an object * * This must be called only once when the frame is about to leave * scope. Any local references other than the one that is kept * are destroyed. If the next line is not "return", you are using * this incorrectly. * * Further calls to the frame will still suceed as we do not * check for operation on a closed frame, but is not advised. */ jobject keep(jobject); /** Create a new global reference to a java object. * * This java reference may be held in a class until the object is * no longer needed. It should be deleted with DeleteGlobalRef * or ReleaseGlobalRef. */ jobject NewGlobalRef(jobject obj); /** Delete a global reference. */ void DeleteGlobalRef(jobject obj); /** Create a new local reference. * * This is only used when promoting a WeakReference to * a local reference. */ jobject NewLocalRef(jobject obj); /** Prematurely delete a local reference. * * This is used when processing an array to keep * the objects in scope from growing. */ void DeleteLocalRef(jobject obj); jweak NewWeakGlobalRef(jobject obj); void DeleteWeakGlobalRef(jweak obj); JNIEnv* getEnv() const { return m_Env; } JPContext* getContext() const { return m_Context; } string toString(jobject o); string toStringUTF8(jstring str); bool equals(jobject o1, jobject o2); jint hashCode(jobject o); jobject collectRectangular(jarray obj); jobject assemble(jobject dims, jobject parts); jobject newArrayInstance(jclass c, jintArray dims); jthrowable getCause(jthrowable th); jstring getMessage(jthrowable th); jint compareTo(jobject obj, jobject obj2); /** * Convert a UTF8 encoded string into Java. * * This returns a local reference. * @param str * @return */ jstring fromStringUTF8(const string& str); jobject callMethod(jobject method, jobject obj, jobject args); jobject toCharArray(jstring jstr); string getFunctional(jclass c); JPClass *findClass(jclass obj); JPClass *findClassByName(const string& name); JPClass *findClassForObject(jobject obj); private: // not implemented JPJavaFrame& operator= (const JPJavaFrame& frame); jint PushLocalFrame(jint); jobject PopLocalFrame(jobject); public: bool ExceptionCheck(); void ExceptionDescribe(); void ExceptionClear(); jthrowable ExceptionOccurred(); jint ThrowNew(jclass clazz, const char* msg); jint Throw(jthrowable th); jobject NewDirectByteBuffer(void* address, jlong capacity); /** NewObjectA */ jobject NewObjectA(jclass a0, jmethodID a1, jvalue* a2); // Monitor int MonitorEnter(jobject a0); int MonitorExit(jobject a0); jclass FindClass(const string& a0); jclass DefineClass(const char* a0, jobject a1, const jbyte* a2, jsize a3); jint RegisterNatives(jclass a0, const JNINativeMethod* a1, jint a2); jboolean IsInstanceOf(jobject a0, jclass a1); jboolean IsAssignableFrom(jclass a0, jclass a1); jsize GetArrayLength(jarray a0); jobject GetObjectArrayElement(jobjectArray a0, jsize a1); jfieldID FromReflectedField(jobject a0); jfieldID GetFieldID(jclass a0, const char* a1, const char* a2); jfieldID GetStaticFieldID(jclass a0, const char* a1, const char* a2); jmethodID FromReflectedMethod(jobject a0); jmethodID GetMethodID(jclass a0, const char* a1, const char* a2); jmethodID GetStaticMethodID(jclass a0, const char* a1, const char* a2); // Void void CallStaticVoidMethodA(jclass a0, jmethodID a1, jvalue* a2); void CallVoidMethodA(jobject a0, jmethodID a1, jvalue* a2); void CallNonvirtualVoidMethodA(jobject a0, jclass a1, jmethodID a2, jvalue* a3); // Bool jboolean GetStaticBooleanField(jclass clazz, jfieldID fid); jboolean GetBooleanField(jobject clazz, jfieldID fid); void SetStaticBooleanField(jclass clazz, jfieldID fid, jboolean val); void SetBooleanField(jobject clazz, jfieldID fid, jboolean val); jboolean CallStaticBooleanMethodA(jclass clazz, jmethodID mid, jvalue* val); jboolean CallBooleanMethodA(jobject obj, jmethodID mid, jvalue* val); jboolean CallNonvirtualBooleanMethodA(jobject obj, jclass claz, jmethodID mid, jvalue* val); jbooleanArray NewBooleanArray(jsize len); void SetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len, jboolean* vals); void GetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len, jboolean* vals); jboolean* GetBooleanArrayElements(jbooleanArray array, jboolean* isCopy); void ReleaseBooleanArrayElements(jbooleanArray, jboolean* v, jint mode); // Byte jbyte GetStaticByteField(jclass clazz, jfieldID fid); jbyte GetByteField(jobject clazz, jfieldID fid); void SetStaticByteField(jclass clazz, jfieldID fid, jbyte val); void SetByteField(jobject clazz, jfieldID fid, jbyte val); jbyte CallStaticByteMethodA(jclass clazz, jmethodID mid, jvalue* val); jbyte CallByteMethodA(jobject obj, jmethodID mid, jvalue* val); jbyte CallNonvirtualByteMethodA(jobject obj, jclass claz, jmethodID mid, jvalue* val); jbyteArray NewByteArray(jsize len); void SetByteArrayRegion(jbyteArray array, jsize start, jsize len, jbyte* vals); void GetByteArrayRegion(jbyteArray array, jsize start, jsize len, jbyte* vals); jbyte* GetByteArrayElements(jbyteArray array, jboolean* isCopy); void ReleaseByteArrayElements(jbyteArray, jbyte* v, jint mode); // Char jchar GetStaticCharField(jclass clazz, jfieldID fid); jchar GetCharField(jobject clazz, jfieldID fid); void SetStaticCharField(jclass clazz, jfieldID fid, jchar val); void SetCharField(jobject clazz, jfieldID fid, jchar val); jchar CallStaticCharMethodA(jclass clazz, jmethodID mid, jvalue* val); jchar CallCharMethodA(jobject obj, jmethodID mid, jvalue* val); jchar CallNonvirtualCharMethodA(jobject obj, jclass claz, jmethodID mid, jvalue* val); jcharArray NewCharArray(jsize len); void SetCharArrayRegion(jcharArray array, jsize start, jsize len, jchar* vals); void GetCharArrayRegion(jcharArray array, jsize start, jsize len, jchar* vals); jchar* GetCharArrayElements(jcharArray array, jboolean* isCopy); void ReleaseCharArrayElements(jcharArray, jchar* v, jint mode); // Short jshort GetStaticShortField(jclass clazz, jfieldID fid); jshort GetShortField(jobject clazz, jfieldID fid); void SetStaticShortField(jclass clazz, jfieldID fid, jshort val); void SetShortField(jobject clazz, jfieldID fid, jshort val); jshort CallStaticShortMethodA(jclass clazz, jmethodID mid, jvalue* val); jshort CallShortMethodA(jobject obj, jmethodID mid, jvalue* val); jshort CallNonvirtualShortMethodA(jobject obj, jclass claz, jmethodID mid, jvalue* val); jshortArray NewShortArray(jsize len); void SetShortArrayRegion(jshortArray array, jsize start, jsize len, jshort* vals); void GetShortArrayRegion(jshortArray array, jsize start, jsize len, jshort* vals); jshort* GetShortArrayElements(jshortArray array, jboolean* isCopy); void ReleaseShortArrayElements(jshortArray, jshort* v, jint mode); // Integer jint GetStaticIntField(jclass clazz, jfieldID fid); jint GetIntField(jobject clazz, jfieldID fid); void SetStaticIntField(jclass clazz, jfieldID fid, jint val); void SetIntField(jobject clazz, jfieldID fid, jint val); jint CallStaticIntMethodA(jclass clazz, jmethodID mid, jvalue* val); jint CallIntMethodA(jobject obj, jmethodID mid, jvalue* val); jint CallNonvirtualIntMethodA(jobject obj, jclass claz, jmethodID mid, jvalue* val); jintArray NewIntArray(jsize len); void SetIntArrayRegion(jintArray array, jsize start, jsize len, jint* vals); void GetIntArrayRegion(jintArray array, jsize start, jsize len, jint* vals); jint* GetIntArrayElements(jintArray array, jboolean* isCopy); void ReleaseIntArrayElements(jintArray, jint* v, jint mode); // Long jlong GetStaticLongField(jclass clazz, jfieldID fid); jlong GetLongField(jobject clazz, jfieldID fid); void SetStaticLongField(jclass clazz, jfieldID fid, jlong val); void SetLongField(jobject clazz, jfieldID fid, jlong val); jlong CallStaticLongMethodA(jclass clazz, jmethodID mid, jvalue* val); jlong CallLongMethodA(jobject obj, jmethodID mid, jvalue* val); jlong CallNonvirtualLongMethodA(jobject obj, jclass claz, jmethodID mid, jvalue* val); jfloat GetStaticFloatField(jclass clazz, jfieldID fid); jlongArray NewLongArray(jsize len); void SetLongArrayRegion(jlongArray array, jsize start, jsize len, jlong* vals); void GetLongArrayRegion(jlongArray array, jsize start, jsize len, jlong* vals); jlong* GetLongArrayElements(jlongArray array, jboolean* isCopy); void ReleaseLongArrayElements(jlongArray, jlong* v, jint mode); // Float jfloat GetFloatField(jobject clazz, jfieldID fid); void SetStaticFloatField(jclass clazz, jfieldID fid, jfloat val); void SetFloatField(jobject clazz, jfieldID fid, jfloat val); jfloat CallStaticFloatMethodA(jclass clazz, jmethodID mid, jvalue* val); jfloat CallFloatMethodA(jobject obj, jmethodID mid, jvalue* val); jfloat CallNonvirtualFloatMethodA(jobject obj, jclass claz, jmethodID mid, jvalue* val); jfloatArray NewFloatArray(jsize len); void SetFloatArrayRegion(jfloatArray array, jsize start, jsize len, jfloat* vals); void GetFloatArrayRegion(jfloatArray array, jsize start, jsize len, jfloat* vals); jfloat* GetFloatArrayElements(jfloatArray array, jboolean* isCopy); void ReleaseFloatArrayElements(jfloatArray, jfloat* v, jint mode); // Double jdouble GetStaticDoubleField(jclass clazz, jfieldID fid); jdouble GetDoubleField(jobject clazz, jfieldID fid); void SetStaticDoubleField(jclass clazz, jfieldID fid, jdouble val); void SetDoubleField(jobject clazz, jfieldID fid, jdouble val); jdouble CallStaticDoubleMethodA(jclass clazz, jmethodID mid, jvalue* val); jdouble CallDoubleMethodA(jobject obj, jmethodID mid, jvalue* val); jdouble CallNonvirtualDoubleMethodA(jobject obj, jclass claz, jmethodID mid, jvalue* val); jdoubleArray NewDoubleArray(jsize len); void SetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len, jdouble* vals); void GetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len, jdouble* vals); jdouble* GetDoubleArrayElements(jdoubleArray array, jboolean* isCopy); void ReleaseDoubleArrayElements(jdoubleArray, jdouble* v, jint mode); // Object jclass GetObjectClass(jobject obj); jobject GetStaticObjectField(jclass clazz, jfieldID fid); jobject GetObjectField(jobject clazz, jfieldID fid); void SetStaticObjectField(jclass clazz, jfieldID fid, jobject val); void SetObjectField(jobject clazz, jfieldID fid, jobject val); jobject CallStaticObjectMethodA(jclass clazz, jmethodID mid, jvalue* val); jobject CallObjectMethodA(jobject obj, jmethodID mid, jvalue* val); jobject CallNonvirtualObjectMethodA(jobject obj, jclass claz, jmethodID mid, jvalue* val); jobjectArray NewObjectArray(jsize a0, jclass a1, jobject a2); void SetObjectArrayElement(jobjectArray a0, jsize a1, jobject a2); // String jstring NewStringUTF(const char* a0); void* GetDirectBufferAddress(jobject obj); jlong GetDirectBufferCapacity(jobject obj); jboolean isBufferReadOnly(jobject obj); jboolean orderBuffer(jobject obj); jclass getClass(jobject obj); /** This returns a UTF16 surogate coded UTF-8 string. */ const char* GetStringUTFChars(jstring a0, jboolean* a1); void ReleaseStringUTFChars(jstring a0, const char* a1); jsize GetStringUTFLength(jstring a0); jboolean isPackage(const string& str); jobject getPackage(const string& str); jobject getPackageObject(jobject pkg, const string& str); jarray getPackageContents(jobject pkg); void newWrapper(JPClass* cls); void registerRef(jobject obj, PyObject* hostRef); void registerRef(jobject obj, void* ref, JCleanupHook cleanup); void clearInterrupt(bool throws); } ; #endif // _JP_JAVA_FRAME_H_ jpype-1.3.0/native/common/include/jp_longtype.h000077500000000000000000000063141405671516700215710ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef _JP_LONG_TYPE_H_ #define _JP_LONG_TYPE_H_ class JPLongType : public JPPrimitiveType { public: JPLongType(); virtual ~JPLongType(); typedef jlong type_t; typedef jlongArray array_t; static inline jlong& field(jvalue& v) { return v.j; } static inline const jlong& field(const jvalue& v) { return v.j; } virtual JPClass* getBoxedClass(JPContext *context) const override { return context->_java_lang_Long; } virtual JPMatch::Type findJavaConversion(JPMatch& match) override; virtual void getConversionInfo(JPConversionInfo &info) override; virtual JPPyObject convertToPythonObject(JPJavaFrame& frame, jvalue val, bool cast) override; virtual JPValue getValueFromObject(const JPValue& obj) override; virtual JPPyObject invokeStatic(JPJavaFrame& frame, jclass, jmethodID, jvalue*) override; virtual JPPyObject invoke(JPJavaFrame& frame, jobject, jclass, jmethodID, jvalue*) override; virtual JPPyObject getStaticField(JPJavaFrame& frame, jclass c, jfieldID fid) override; virtual void setStaticField(JPJavaFrame& frame, jclass c, jfieldID fid, PyObject* val) override; virtual JPPyObject getField(JPJavaFrame& frame, jobject c, jfieldID fid) override; virtual void setField(JPJavaFrame& frame, jobject c, jfieldID fid, PyObject* val) override; virtual jarray newArrayOf(JPJavaFrame& frame, jsize size) override; virtual void setArrayRange(JPJavaFrame& frame, jarray, jsize start, jsize length, jsize step, PyObject *sequence) override; virtual JPPyObject getArrayItem(JPJavaFrame& frame, jarray, jsize ndx) override; virtual void setArrayItem(JPJavaFrame& frame, jarray, jsize ndx, PyObject* val) override; virtual char getTypeCode() override { return 'J'; } // GCOVR_EXCL_START // Required but not exercised currently virtual jlong getAsLong(jvalue v) override { return (jlong) field(v); } // GCOVR_EXCL_STOP virtual jdouble getAsDouble(jvalue v) override { return (jdouble) field(v); } static jlong assertRange(const jlong& l) { return l; } virtual void getView(JPArrayView& view) override; virtual void releaseView(JPArrayView& view) override; virtual const char* getBufferFormat() override; virtual ssize_t getItemSize() override; virtual void copyElements(JPJavaFrame &frame, jarray a, jsize start, jsize len, void* memory, int offset) override; virtual PyObject *newMultiArray(JPJavaFrame &frame, JPPyBuffer &buffer, int subs, int base, jobject dims) override; } ; #endif // _JP_LONG_TYPE_H_jpype-1.3.0/native/common/include/jp_match.h000066400000000000000000000035301405671516700210160ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef JP_MATCH_H #define JP_MATCH_H class JPConversion; class JPMatch { public: enum Type { _none = 0, _explicit = 1, _implicit = 2, _exact = 3 } ; public: JPMatch(); JPMatch(JPJavaFrame *frame, PyObject *object); JPContext *getContext() { if (frame == NULL) return NULL; return frame->getContext(); } /** * Get the Java slot associated with the Python object. * * Thus uses caching. * * @return the Java slot or 0 if not available. */ JPValue *getJavaSlot(); jvalue convert(); public: JPMatch::Type type; JPConversion *conversion; JPJavaFrame *frame; PyObject *object; JPValue *slot; void *closure; } ; class JPMethodCache { public: long m_Hash; JPMethod* m_Overload; } ; class JPMethodMatch : public JPMethodCache { public: JPMethodMatch(JPJavaFrame &frame, JPPyObjectVector& args, bool callInstance); JPMatch& operator[](size_t i) { return m_Arguments[i]; } const JPMatch& operator[](size_t i) const { return m_Arguments[i]; } std::vector m_Arguments; JPMatch::Type m_Type; bool m_IsVarIndirect; char m_Offset; char m_Skip; } ; #endif /* JP_MATCH_H */jpype-1.3.0/native/common/include/jp_method.h000066400000000000000000000063231405671516700212050ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef _JPMETHOD_H_ #define _JPMETHOD_H_ #include "jp_modifier.h" class JPMethod; class JPMethod : public JPResource { friend class JPMethodDispatch; public: JPMethod(); JPMethod(JPJavaFrame& frame, JPClass* claz, const string& name, jobject mth, jmethodID mid, JPMethodList& moreSpecific, jint modifiers); virtual ~JPMethod(); void setParameters( JPClass *returnType, JPClassList parameterTypes); /** Check to see if this overload matches the argument list. * * @param frame is the scope to hold Java local variables. * @param match holds the details of the match that is found. * @param isInstance is true if the first argument is an instance object. * @param args is a list of arguments including the instance. * * @return the quality of the match. * */ JPMatch::Type matches(JPJavaFrame &frame, JPMethodMatch& match, bool isInstance, JPPyObjectVector& args); JPPyObject invoke(JPJavaFrame &frame, JPMethodMatch& match, JPPyObjectVector& arg, bool instance); JPPyObject invokeCallerSensitive(JPMethodMatch& match, JPPyObjectVector& arg, bool instance); JPValue invokeConstructor(JPJavaFrame &frame, JPMethodMatch& match, JPPyObjectVector& arg); bool isAbstract() const { return JPModifier::isAbstract(m_Modifiers); } bool isConstructor() const { return JPModifier::isConstructor(m_Modifiers); } bool isInstance() const { return !JPModifier::isStatic(m_Modifiers) && !JPModifier::isConstructor(m_Modifiers); } bool isFinal() const { return JPModifier::isFinal(m_Modifiers); } bool isStatic() const { return JPModifier::isStatic(m_Modifiers); } bool isVarArgs() const { return JPModifier::isVarArgs(m_Modifiers); } bool isCallerSensitive() const { return JPModifier::isCallerSensitive(m_Modifiers); } string toString() const; string matchReport(JPPyObjectVector& args); bool checkMoreSpecificThan(JPMethod* other) const; jobject getJava() { return m_Method.get(); } private: void packArgs(JPJavaFrame &frame, JPMethodMatch &match, vector &v, JPPyObjectVector &arg); void ensureTypeCache(); JPMethod(const JPMethod& o); JPMethod& operator=(const JPMethod&) ; private: JPClass* m_Class; string m_Name; JPObjectRef m_Method; jmethodID m_MethodID; JPClass* m_ReturnType; JPClassList m_ParameterTypes; JPMethodList m_MoreSpecificOverloads; jint m_Modifiers; } ; #endif // _JPMETHODOVERLOAD_H_jpype-1.3.0/native/common/include/jp_methoddispatch.h000066400000000000000000000045641405671516700227320ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef _JPMETHODDISPATCH_H_ #define _JPMETHODDISPATCH_H_ #include "jp_class.h" class JPMethodDispatch : public JPResource { public: /** * Create a new method based on class and a name; */ JPMethodDispatch(JPClass *clazz, const string& name, JPMethodList& overloads, jint modifiers); virtual ~JPMethodDispatch(); private: JPMethodDispatch(const JPMethodDispatch& method); JPMethodDispatch& operator=(const JPMethodDispatch& method); public: JPClass* getClass() { return m_Class; } JPContext* getContext() { return m_Class->getContext(); } const string& getName() const; bool hasStatic() const { return JPModifier::isStatic(m_Modifiers); } bool isBeanMutator() const { return JPModifier::isBeanMutator(m_Modifiers); } bool isBeanAccessor() const { return JPModifier::isBeanAccessor(m_Modifiers); } JPPyObject invoke(JPJavaFrame& frame, JPPyObjectVector& vargs, bool instance); JPValue invokeConstructor(JPJavaFrame& frame, JPPyObjectVector& vargs); bool matches(JPJavaFrame& frame, JPPyObjectVector& args, bool instance); string matchReport(JPPyObjectVector& sequence); const JPMethodList& getMethodOverloads() { return m_Overloads; } private: /** Search for a matching overload. * * @param searchInstance is true if the first argument is to be skipped * when matching with a non-static. */ bool findOverload(JPJavaFrame& frame, JPMethodMatch &bestMatch, JPPyObjectVector& vargs, bool searchInstance, bool raise); void dumpOverloads(); JPClass* m_Class; string m_Name; JPMethodList m_Overloads; jlong m_Modifiers; JPMethodCache m_LastCache; } ; #endif // _JPMETHODDISPATCH_H_jpype-1.3.0/native/common/include/jp_modifier.h000066400000000000000000000074161405671516700215270ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef JP_MODIFIER_H #define JP_MODIFIER_H #ifdef __cplusplus extern "C" { #endif namespace JPModifier { /* https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.1-200-E.1 * https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.5-200-A.1 * https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.6-200-A.1 */ inline bool isPublic(jlong modifier) { return (modifier & 0x0001) == 0x0001; } inline bool isPrivate(jlong modifier) { return (modifier & 0x0002) == 0x0002; } inline bool isProtected(jlong modifier) { return (modifier & 0x0004) == 0x0004; } inline bool isStatic(jlong modifier) { return (modifier & 0x0008) == 0x0008; } inline bool isFinal(jlong modifier) { return (modifier & 0x0010) == 0x0010; } inline bool isSuper(jlong modifier) { return (modifier & 0x0020) == 0x0020; } inline bool isVolatile(jlong modifier) { return (modifier & 0x0040) == 0x0040; } // fields inline bool isBridge(jlong modifier) { return (modifier & 0x0040) == 0x0040; } // methods inline bool isTransient(jlong modifier) { return (modifier & 0x0080) == 0x0080; } // fields inline bool isVarArgs(jlong modifier) { return (modifier & 0x0080) == 0x0080; } //methods inline bool isNative(jlong modifier) { return (modifier & 0x0100) == 0x0100; } inline bool isInterface(jlong modifier) { return (modifier & 0x0200) == 0x0200; } inline bool isAbstract(jlong modifier) { return (modifier & 0x0400) == 0x0400; } inline bool isStrict(jlong modifier) { return (modifier & 0x0800) == 0x0800; } inline bool isSynthetic(jlong modifier) { return (modifier & 0x1000) == 0x1000; } inline bool isAnnotation(jlong modifier) { return (modifier & 0x2000) == 0x2000; } inline bool isEnum(jlong modifier) { return (modifier & 0x4000) == 0x4000; } inline bool isModule(jlong modifier) { return (modifier & 0x8000) == 0x8000; } /* JPype flags (must match ModifierCodes sections) */ inline bool isSpecial(jlong modifier) { return (modifier & 0x00010000) == 0x00010000; } inline bool isThrowable(jlong modifier) { return (modifier & 0x00020000) == 0x00020000; } inline bool isSerializable(jlong modifier) { return (modifier & 0x00040000) == 0x00040000; } inline bool isAnonymous(jlong modifier) { return (modifier & 0x00080000) == 0x00080000; } inline bool isFunctional(jlong modifier) { return (modifier & 0x00100000) == 0x00100000; } inline bool isCallerSensitive(jlong modifier) { return (modifier & 0x00200000) == 0x00200000; } inline bool isPrimitiveArray(jlong modifier) { return (modifier & 0x00400000) == 0x00400000; } inline bool isComparable(jlong modifier) { return (modifier & 0x00800000) == 0x00800000; } inline bool isBuffer(jlong modifier) { return (modifier & 0x01000000) == 0x01000000; } inline bool isConstructor(jlong modifier) { return (modifier & 0x10000000) == 0x10000000; } inline bool isBeanAccessor(jlong modifier) { return (modifier & 0x20000000) == 0x20000000; } inline bool isBeanMutator(jlong modifier) { return (modifier & 0x40000000) == 0x40000000; } } #ifdef __cplusplus } #endif #endif /* JP_MODIFIER_H */jpype-1.3.0/native/common/include/jp_monitor.h000066400000000000000000000020221405671516700214040ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef _JPMONITOR_H_ #define _JPMONITOR_H_ class JPMonitor { public: JPMonitor(JPContext* context, jobject obj); virtual ~JPMonitor(); void enter(); void exit(); JPContext* getContext() { return m_Context; } private: JPContext* m_Context; JPObjectRef m_Value; } ; #endif // _JPMONITOR_H_jpype-1.3.0/native/common/include/jp_numbertype.h000066400000000000000000000022641405671516700221170ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef _JPNUMBERTYPE_H_ #define _JPNUMBERTYPE_H_ /** * Wrapper for Class */ class JPNumberType : public JPClass { public: JPNumberType(JPJavaFrame& frame, jclass clss, const string& name, JPClass* super, JPClassList& interfaces, jint modifiers); virtual~ JPNumberType(); JPMatch::Type findJavaConversion(JPMatch& match) override; virtual void getConversionInfo(JPConversionInfo &info) override; } ; #endif // _JPNUMBERTYPE_H_jpype-1.3.0/native/common/include/jp_objecttype.h000066400000000000000000000025531405671516700220760ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef _JPOBJECTTYPE_H_ #define _JPOBJECTTYPE_H_ /** * Wrapper for Class * * Primitive types can implicitly cast to this type as * well as class wrappers, thus we need a specialized * wrapper. This class should not be used outside of * the JPTypeManager. * */ class JPObjectType : public JPClass { public: JPObjectType(JPJavaFrame& frame, jclass clss, const string& name, JPClass* super, JPClassList& interfaces, jint modifiers); virtual~ JPObjectType(); JPMatch::Type findJavaConversion(JPMatch& match) override; void getConversionInfo(JPConversionInfo &info) override; } ; #endif // _JPOBJECTTYPE_H_jpype-1.3.0/native/common/include/jp_platform.h000066400000000000000000000021421405671516700215440ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef _JPENV_H_ #define _JPENV_H_ /** * the platform adapter's implementation is chosen by the JPYPE_??? macros */ class JPPlatformAdapter { public: virtual ~JPPlatformAdapter(); virtual void loadLibrary(const char* path) = 0; virtual void unloadLibrary() = 0; virtual void* getSymbol(const char* name) = 0; static JPPlatformAdapter* getAdapter(); } ; #endif // _JPENV_H_jpype-1.3.0/native/common/include/jp_primitive_accessor.h000066400000000000000000000207331405671516700236200ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef JP_PRIMITIVE_ACCESSOR_H #define JP_PRIMITIVE_ACCESSOR_H #include #include "jp_exception.h" #include "jp_javaframe.h" #include "jp_match.h" template class JPPrimitiveArrayAccessor { typedef void (JPJavaFrame::*releaseFnc)(array_t, ptr_t, jint); typedef ptr_t (JPJavaFrame::*accessFnc)(array_t, jboolean*); JPJavaFrame& _frame; array_t _array; ptr_t _elem; releaseFnc _release; jboolean _iscopy; public: JPPrimitiveArrayAccessor(JPJavaFrame& frame, jarray array, accessFnc access, releaseFnc release) : _frame(frame), _array((array_t) array), _release(release) { _elem = ((&_frame)->*access)(_array, &_iscopy); } ~JPPrimitiveArrayAccessor() { // This is fallback if commit or abort is not called. // It should only occur in cases where a throw has // already been issued. try { if (_array) ((&_frame)->*_release)(_array, _elem, JNI_ABORT); } catch (JPypeException&) // GCOVR_EXCL_LINE { // We can't throw here because it would abort. // But this is called on a non-op release, so // we will just eat it } } jsize size() { return _frame.GetArrayLength(_array); } ptr_t get() { return _elem; } void commit() { // Prevent the dtor from calling a second time array_t a = _array; _array = 0; ((&_frame)->*_release)(a, _elem, 0); } void abort() { // Prevent the dtor from calling a second time array_t a = _array; _array = 0; ((&_frame)->*_release)(a, _elem, JNI_ABORT); } } ; template PyObject *convertMultiArray( JPJavaFrame &frame, JPPrimitiveType* cls, void (*pack)(type_t*, jvalue), const char* code, JPPyBuffer &buffer, int subs, int base, jobject dims) { JPContext *context = frame.getContext(); Py_buffer& view = buffer.getView(); jconverter converter = getConverter(view.format, (int) view.itemsize, code); if (converter == NULL) { PyErr_Format(PyExc_TypeError, "No type converter found"); return NULL; } // Reserve space for array. jobjectArray contents = (jobjectArray) context->_java_lang_Object->newArrayOf(frame, subs); std::vector indices(view.ndim); int u = view.ndim - 1; int k = 0; jarray a0 = cls->newArrayOf(frame, base); frame.SetObjectArrayElement(contents, k++, a0); jboolean isCopy; void *mem = frame.getEnv()->GetPrimitiveArrayCritical(a0, &isCopy); JP_TRACE_JAVA("GetPrimitiveArrayCritical", mem); type_t *dest = (type_t*) mem; Py_ssize_t step; if (view.strides == NULL) step = view.itemsize; else step = view.strides[u]; // Align with the first element in the array char *src = buffer.getBufferPtr(indices); // Traverse the array while (true) { if (indices[u] == view.shape[u]) { int j; for (j = 0; j < u; ++j) { indices[u - j - 1]++; if (indices[u - j - 1] < view.shape[u - j - 1]) break; indices[u - j - 1] = 0; } // Commit the current section indices[u] = 0; JP_TRACE_JAVA("ReleasePrimitiveArrayCritical", mem); frame.getEnv()->ReleasePrimitiveArrayCritical(a0, mem, JNI_COMMIT); frame.DeleteLocalRef(a0); // If we hit the shape of the uppermost we are done if (j == u) break; a0 = cls->newArrayOf(frame, base); frame.SetObjectArrayElement(contents, k++, a0); mem = frame.getEnv()->GetPrimitiveArrayCritical(a0, &isCopy); JP_TRACE_JAVA("GetPrimitiveArrayCritical", mem); dest = (type_t*) mem; src = buffer.getBufferPtr(indices); } pack(dest, converter(src)); src += step; dest++; indices[u]++; } // Assemble it into a multidimensional array jobject out = frame.assemble(dims, contents); // Convert it to Python JPClass *type = context->_java_lang_Object; if (out != NULL) type = frame.findClassForObject(out); jvalue v; v.l = out; return type->convertToPythonObject(frame, v, false).keep(); } template class JPConversionLong : public JPIndexConversion { public: virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) override { if (!PyLong_CheckExact(match.object) && !PyIndex_Check(match.object)) return match.type = JPMatch::_none; match.conversion = this; return match.type = JPMatch::_implicit; } virtual jvalue convert(JPMatch &match) override { jvalue res; if (match.type == JPMatch::_exact) { jlong val = (jlong) PyLong_AsUnsignedLongLongMask(match.object); if (val == -1) JP_PY_CHECK(); // GCOVR_EXCL_LINE base_t::field(res) = (typename base_t::type_t) val; } else { jlong val = (jlong) PyLong_AsLongLong(match.object); if (val == -1) JP_PY_CHECK(); // GCOVR_EXCL_LINE base_t::field(res) = (typename base_t::type_t) base_t::assertRange(val); } return res; } } ; template class JPConversionLongNumber : public JPConversionLong { public: virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) override { if (!PyNumber_Check(match.object)) return match.type = JPMatch::_none; match.conversion = this; return match.type = JPMatch::_explicit; } virtual void getInfo(JPClass *cls, JPConversionInfo &info) override { PyObject *typing = PyImport_AddModule("jpype.protocol"); JPPyObject proto = JPPyObject::call(PyObject_GetAttrString(typing, "SupportsFloat")); PyList_Append(info.expl, proto.get()); } virtual jvalue convert(JPMatch &match) override { JPPyObject obj = JPPyObject::call(PyNumber_Long(match.object)); match.object = obj.get(); return JPConversionLong::convert(match); } } ; template class JPConversionLongWiden : public JPConversion { public: // GCOVR_EXCL_START virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) override { return JPMatch::_none; // Not used } virtual void getInfo(JPClass *cls, JPConversionInfo &info) override { // Not used } // GCOVR_EXCL_STOP virtual jvalue convert(JPMatch &match) override { JPValue *value = match.getJavaSlot(); jvalue ret; base_t::field(ret) = (typename base_t::type_t) ((JPPrimitiveType*) value->getClass())->getAsLong(value->getValue()); return ret; } } ; template class JPConversionAsFloat : public JPNumberConversion { public: virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) override { if (!PyNumber_Check(match.object)) return match.type = JPMatch::_none; match.conversion = this; return match.type = JPMatch::_implicit; } virtual jvalue convert(JPMatch &match) override { jvalue res; double val = PyFloat_AsDouble(match.object); if (val == -1.0) JP_PY_CHECK(); // GCOVR_EXCL_LINE base_t::field(res) = (typename base_t::type_t) val; return res; } } ; template class JPConversionLongAsFloat : public JPConversion { public: virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) override { if (!PyLong_Check(match.object)) return match.type = JPMatch::_none; match.conversion = this; return match.type = JPMatch::_implicit; } virtual void getInfo(JPClass *cls, JPConversionInfo &info) override { PyList_Append(info.implicit, (PyObject*) & PyLong_Type); } virtual jvalue convert(JPMatch &match) override { jvalue res; jdouble v = PyLong_AsDouble(match.object); if (v == -1.0) JP_PY_CHECK(); // GCOVR_EXCL_LINE base_t::field(res) = (typename base_t::type_t) v; return res; } } ; template class JPConversionFloatWiden : public JPConversion { public: // GCOVR_EXCL_START virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) override { return JPMatch::_none; // not used } virtual void getInfo(JPClass *cls, JPConversionInfo &info) override { } // GCOVR_EXCL_STOP virtual jvalue convert(JPMatch &match) override { JPValue *value = match.getJavaSlot(); jvalue ret; base_t::field(ret) = (typename base_t::type_t) ((JPPrimitiveType*) value->getClass())->getAsDouble(value->getValue()); return ret; } } ; #endif /* JP_PRIMITIVE_ACCESSOR_H */ jpype-1.3.0/native/common/include/jp_primitivetype.h000066400000000000000000000034201405671516700226320ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef _JPPRIMITIVETYPE_H_ #define _JPPRIMITIVETYPE_H_ #include "jp_boxedtype.h" class JPPrimitiveType : public JPClass { protected: JPPrimitiveType(const string& name); virtual ~JPPrimitiveType(); public: virtual bool isPrimitive() const override; virtual JPClass* getBoxedClass(JPContext *context) const = 0; virtual char getTypeCode() = 0; virtual jlong getAsLong(jvalue v) = 0; virtual jdouble getAsDouble(jvalue v) = 0; void setClass(JPJavaFrame& frame, jclass o) { m_Context = frame.getContext(); m_Class = JPClassRef(frame, o); } virtual void getView(JPArrayView& view) = 0; virtual void releaseView(JPArrayView& view) = 0; virtual const char* getBufferFormat() = 0; virtual ssize_t getItemSize() = 0; virtual void copyElements(JPJavaFrame &frame, jarray a, jsize start, jsize len, void* memory, int offset) = 0; virtual PyObject *newMultiArray(JPJavaFrame &frame, JPPyBuffer& view, int subs, int base, jobject dims) = 0; // Helper for Long types PyObject *convertLong(PyTypeObject* wrapper, PyLongObject* tmp); } ; #endifjpype-1.3.0/native/common/include/jp_proxy.h000066400000000000000000000050311405671516700211010ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef _JPPROXY_H_ #define _JPPROXY_H_ struct PyJPProxy; class JPProxy; class JPFunctional; class JPProxy { public: friend class JPProxyType; JPProxy(JPContext* context, PyJPProxy* inst, JPClassList& intf); virtual ~JPProxy(); const JPClassList& getInterfaces() const { return m_InterfaceClasses; } jvalue getProxy(); JPContext* getContext() { return m_Context; } virtual JPPyObject getCallable(const string& cname) = 0; static void releaseProxyPython(void* host); protected: JPContext* m_Context; PyJPProxy* m_Instance; JPObjectRef m_Proxy; JPClassList m_InterfaceClasses; jweak m_Ref; } ; class JPProxyDirect : public JPProxy { public: JPProxyDirect(JPContext* context, PyJPProxy* inst, JPClassList& intf); virtual ~JPProxyDirect(); virtual JPPyObject getCallable(const string& cname) override; } ; class JPProxyIndirect : public JPProxy { public: JPProxyIndirect(JPContext* context, PyJPProxy* inst, JPClassList& intf); virtual ~JPProxyIndirect(); virtual JPPyObject getCallable(const string& cname) override; } ; class JPProxyFunctional : public JPProxy { public: JPProxyFunctional(JPContext* context, PyJPProxy* inst, JPClassList& intf); virtual ~JPProxyFunctional(); virtual JPPyObject getCallable(const string& cname) override; private: JPFunctional *m_Functional; } ; /** Special wrapper for round trip returns */ class JPProxyType : public JPClass { public: JPProxyType(JPJavaFrame& frame, jclass clss, const string& name, JPClass* super, JPClassList& interfaces, jint modifiers); virtual~ JPProxyType(); public: // JPClass implementation virtual JPPyObject convertToPythonObject(JPJavaFrame& frame, jvalue val, bool cast) override; private: JPClassRef m_ProxyClass; jmethodID m_GetInvocationHandlerID; jfieldID m_InstanceID; } ; #endif // JPPROXY_Hjpype-1.3.0/native/common/include/jp_reference_queue.h000066400000000000000000000020341405671516700230620ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef JP_REFERENCE_QUEUE_H__ #define JP_REFERENCE_QUEUE_H__ #include namespace JPReferenceQueue { void registerRef(JPJavaFrame &frame, jobject obj, PyObject* targetRef); void registerRef(JPJavaFrame &frame, jobject obj, void* host, JCleanupHook func); } ; // end of namespace JPReferenceQueue #endifjpype-1.3.0/native/common/include/jp_shorttype.h000077500000000000000000000063541405671516700217750ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef _JP_SHORT_TYPE_H_ #define _JP_SHORT_TYPE_H_ class JPShortType : public JPPrimitiveType { public: JPShortType(); virtual ~JPShortType(); typedef jshort type_t; typedef jshortArray array_t; static inline jshort& field(jvalue& v) { return v.s; } static inline const jshort& field(const jvalue& v) { return v.s; } virtual JPClass* getBoxedClass(JPContext *context) const override { return context->_java_lang_Short; } virtual JPMatch::Type findJavaConversion(JPMatch &match) override; virtual void getConversionInfo(JPConversionInfo &info) override; virtual JPPyObject convertToPythonObject(JPJavaFrame& frame, jvalue val, bool cast) override; virtual JPValue getValueFromObject(const JPValue& obj) override; virtual JPPyObject invokeStatic(JPJavaFrame& frame, jclass, jmethodID, jvalue*) override; virtual JPPyObject invoke(JPJavaFrame& frame, jobject, jclass, jmethodID, jvalue*) override; virtual JPPyObject getStaticField(JPJavaFrame& frame, jclass c, jfieldID fid) override; virtual void setStaticField(JPJavaFrame& frame, jclass c, jfieldID fid, PyObject* val) override; virtual JPPyObject getField(JPJavaFrame& frame, jobject c, jfieldID fid) override; virtual void setField(JPJavaFrame& frame, jobject c, jfieldID fid, PyObject* val) override; virtual jarray newArrayOf(JPJavaFrame& frame, jsize size) override; virtual void setArrayRange(JPJavaFrame& frame, jarray, jsize start, jsize length, jsize step, PyObject *sequence) override; virtual JPPyObject getArrayItem(JPJavaFrame& frame, jarray, jsize ndx) override; virtual void setArrayItem(JPJavaFrame& frame, jarray, jsize ndx, PyObject* val) override; virtual char getTypeCode() override { return 'S'; } virtual jlong getAsLong(jvalue v) override { return field(v); } virtual jdouble getAsDouble(jvalue v) override { return field(v); } template static T assertRange(const T& l) { if (l < -32768 || l > 32767) { JP_RAISE(PyExc_OverflowError, "Cannot convert value to Java short"); } return l; } virtual void getView(JPArrayView& view) override; virtual void releaseView(JPArrayView& view) override; virtual const char* getBufferFormat() override; virtual ssize_t getItemSize() override; virtual void copyElements(JPJavaFrame &frame, jarray a, jsize start, jsize len, void* memory, int offset) override; virtual PyObject *newMultiArray(JPJavaFrame &frame, JPPyBuffer &buffer, int subs, int base, jobject dims) override; } ; #endif // _JP_SHORT_TYPE_H_jpype-1.3.0/native/common/include/jp_stringtype.h000066400000000000000000000025041405671516700221320ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef JP_STRINGCLASS_H #define JP_STRINGCLASS_H class JPStringType : public JPClass { public: JPStringType(JPJavaFrame& frame, jclass clss, const string& name, JPClass* super, JPClassList& interfaces, jint modifiers); virtual ~JPStringType(); public: virtual JPPyObject convertToPythonObject(JPJavaFrame& frame, jvalue val, bool cast) override; JPMatch::Type findJavaConversion(JPMatch& match) override; virtual void getConversionInfo(JPConversionInfo &info) override; virtual JPValue newInstance(JPJavaFrame& frame, JPPyObjectVector& args) override; } ; #endif /* JP_STRINGTYPE_H */jpype-1.3.0/native/common/include/jp_tracer.h000066400000000000000000000103101405671516700211740ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef _JP_TRACER_H__ #define _JP_TRACER_H__ #include #include // GCOVR_EXCL_START #ifdef JP_TRACING_ENABLE #define JP_TRACE_IN_C(...) \ JPypeTracer _trace(__VA_ARGS__); try { #define JP_TRACE_OUT_C } \ catch(...) { _trace.gotError(JP_STACKINFO()); throw; } #define JP_TRACE_IN(...) \ JPypeTracer _trace(__VA_ARGS__); \ try { do {} while (0) #define JP_TRACE_OUT \ } \ catch(...) { _trace.gotError(JP_STACKINFO()); throw; } #define JP_TRACE(...) JPTracer::trace(__VA_ARGS__) #define JP_TRACE_LOCKS(...) JPypeTracer::traceLocks(__VA_ARGS__) #define JP_TRACE_PY(m, obj) JPypeTracer::tracePythonObject(m, obj) #define JP_TRACE_JAVA(m, obj) JPypeTracer::traceJavaObject(m, obj) #else #ifndef JP_INSTRUMENTATION #define JP_TRACE_IN(...) try { do {} while (0) #endif #define JP_TRACE_OUT } catch (JPypeException &ex) { ex.from(JP_STACKINFO()); throw; } #define JP_TRACE(...) #define JP_TRACE_LOCKS(...) #define JP_TRACE_PY(m, obj) #define JP_TRACE_JAVA(m, obj) #endif // Enable this option to get all the py referencing information #define JP_ENABLE_TRACE_PY class JPypeTracer { private: string m_Name; bool m_Error; JPypeTracer *m_Last; public: JPypeTracer(const char *name, void *ref = 0); ~JPypeTracer(); void gotError(const JPStackInfo& info) { m_Error = true; try { throw; // lgtm [cpp/rethrow-no-exception] } catch (JPypeException& ex) { ex.from(info); throw; } } static void traceJavaObject(const char *msg, const void* obj); static void tracePythonObject(const char *msg, PyObject *ref); static void traceLocks(const string& msg, void *ref); static void trace1(const char *src, const char *msg); static void trace2(const char *msg1, const char *msg2); private: static void traceIn(const char *msg, void *ref); static void traceOut(const char *msg, bool error); } ; extern "C" int _PyJPModule_trace; namespace JPTracer { template inline void trace(const T& msg) { if ((_PyJPModule_trace & 1) == 0) return; std::stringstream str; str << msg; JPypeTracer::trace1(NULL, str.str().c_str()); } inline void trace(const char *msg) { if ((_PyJPModule_trace & 1) == 0) return; JPypeTracer::trace1(NULL, msg); } template inline void trace(const T1& msg1, const T2 & msg2) { if ((_PyJPModule_trace & 1) == 0) return; std::stringstream str; str << msg1 << " " << msg2; JPypeTracer::trace1(NULL, str.str().c_str()); } inline void trace(const char *msg1, const char *msg2) { if ((_PyJPModule_trace & 1) == 0) return; JPypeTracer::trace2(msg1, msg2); } template inline void trace(const T1& msg1, const T2& msg2, const T3 & msg3) { if ((_PyJPModule_trace & 1) == 0) return; std::stringstream str; str << msg1 << " " << msg2 << " " << msg3; JPypeTracer::trace1(NULL, str.str().c_str()); } template inline void trace(const T1& msg1, const T2& msg2, const T3& msg3, const T4 & msg4) { if ((_PyJPModule_trace & 1) == 0) return; std::stringstream str; str << msg1 << " " << msg2 << " " << msg3 << " " << msg4; JPypeTracer::trace1(NULL, str.str().c_str()); } template inline void trace(const T1& msg1, const T2& msg2, const T3& msg3, const T4& msg4, const T5 & msg5) { if ((_PyJPModule_trace & 1) == 0) return; std::stringstream str; str << msg1 << " " << msg2 << " " << msg3 << " " << msg4 << " " << msg5; JPypeTracer::trace1(NULL, str.str().c_str()); } } // GCOVR_EXCL_STOP #endif // _JP_TRACER_H__jpype-1.3.0/native/common/include/jp_typemanager.h000066400000000000000000000031421405671516700222350ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef _JPTYPE_MANAGER_H_ #define _JPTYPE_MANAGER_H_ /** * These functions will manage the cache of found type, be it primitive types, class types or the "magic" types. */ class JPTypeManager { friend class JPContext; public: /** * Initialize the type manager caches */ explicit JPTypeManager(JPJavaFrame& frame); ~JPTypeManager(); /** * Find a class using a native name. * * The pointer returned is NOT owned by the caller */ JPClass* findClass(jclass cls); JPClass* findClassByName(const string& str); JPClass* findClassForObject(jobject obj); void populateMethod(void* method, jobject obj); void populateMembers(JPClass* cls); private: JPContext* m_Context; JPObjectRef m_JavaTypeManager; jmethodID m_FindClass; jmethodID m_FindClassByName; jmethodID m_FindClassForObject; jmethodID m_PopulateMethod; jmethodID m_PopulateMembers; } ; #endif // _JPCLASS_H_jpype-1.3.0/native/common/include/jp_value.h000066400000000000000000000033321405671516700210360ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef _JPVALUE_H_ #define _JPVALUE_H_ #include "jp_class.h" #include "jp_javaframe.h" /** Lightweight representative of a jvalue with its corresponding class. * This should not have any memory management. The user of the class * must take a global reference if needed. */ class JPValue { public: JPValue() : m_Class(NULL) { m_Value.l = 0; } JPValue(JPClass* clazz, const jvalue& value) : m_Class(clazz), m_Value(value) { } JPValue(JPClass* clazz, jobject value) : m_Class(clazz) { m_Value.l = value; } ~JPValue() { } JPClass* getClass() const { return m_Class; } jvalue& getValue() { return m_Value; } const jvalue& getValue() const { return m_Value; } jobject getJavaObject() const; operator jvalue&() { return m_Value; } operator const jvalue&() const { return m_Value; } JPValue& global(JPJavaFrame& frame) { m_Value.l = frame.NewGlobalRef(m_Value.l); return *this; } private: JPClass* m_Class; jvalue m_Value; } ; #endif // _JPVALUE_H_ jpype-1.3.0/native/common/include/jp_voidtype.h000077500000000000000000000053461405671516700215770ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef _JP_VOID_TYPE_H_ #define _JP_VOID_TYPE_H_ class JPVoidType : public JPPrimitiveType { public: JPVoidType(); virtual ~JPVoidType(); virtual JPClass* getBoxedClass(JPContext *context) const override { return context->_java_lang_Void; } virtual JPMatch::Type findJavaConversion(JPMatch &match) override; virtual JPPyObject convertToPythonObject(JPJavaFrame& frame, jvalue val, bool cast) override; virtual JPPyObject invokeStatic(JPJavaFrame& frame, jclass, jmethodID, jvalue*) override; virtual JPPyObject invoke(JPJavaFrame& frame, jobject, jclass, jmethodID, jvalue*) override; virtual JPPyObject getStaticField(JPJavaFrame& frame, jclass c, jfieldID fid) override; virtual void setStaticField(JPJavaFrame& frame, jclass c, jfieldID fid, PyObject* val) override; virtual JPPyObject getField(JPJavaFrame& frame, jobject c, jfieldID fid) override; virtual void setField(JPJavaFrame& frame, jobject c, jfieldID fid, PyObject* val) override; virtual jarray newArrayOf(JPJavaFrame& frame, jsize size) override; virtual void setArrayRange(JPJavaFrame& frame, jarray, jsize start, jsize length, jsize step, PyObject *sequence) override; virtual JPPyObject getArrayItem(JPJavaFrame& frame, jarray, jsize ndx) override; virtual void setArrayItem(JPJavaFrame& frame, jarray, jsize ndx, PyObject* val) override; virtual JPValue getValueFromObject(const JPValue& obj) override; virtual char getTypeCode() override; virtual jlong getAsLong(jvalue v) override; virtual jdouble getAsDouble(jvalue v) override; virtual void getView(JPArrayView& view) override; virtual void releaseView(JPArrayView& view) override; virtual const char* getBufferFormat() override; virtual ssize_t getItemSize() override; virtual void copyElements(JPJavaFrame &frame, jarray a, jsize start, jsize len, void* memory, int offset) override; virtual PyObject *newMultiArray(JPJavaFrame &frame, JPPyBuffer& view, int subs, int base, jobject dims) override; } ; #endif // _JP_VOID_TYPE_H_jpype-1.3.0/native/common/include/jpype.h000066400000000000000000000135221405671516700203620ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef _JPYPE_H_ #define _JPYPE_H_ #ifdef __GNUC__ // Python requires char* but C++ string constants are const char* #pragma GCC diagnostic ignored "-Wwrite-strings" #endif #ifdef WIN32 #ifndef __GNUC__ // Then this must mean a variant of GCC on win32 ... #pragma warning (disable:4786) #endif #if defined(__CYGWIN__) // jni_md.h does not work for cygwin. Use this instead. #elif defined(__GNUC__) // JNICALL causes problem for function prototypes .. since I am not defining any JNI methods there is no need for it #undef JNICALL #define JNICALL #endif #endif #include // Define this and use to allow destructors to throw in C++11 or later #if defined(_MSC_VER) // Visual Studio C++ does not seem have changed __cplusplus since 1997 #if (_MSVC_LAND >= 201402) #define NO_EXCEPT_FALSE noexcept(false) #else #define NO_EXCEPT_FALSE throw(JPypeException) #endif #else // For all the compilers than understand standards #if (__cplusplus >= 201103L) #define NO_EXCEPT_FALSE noexcept(false) #else #define NO_EXCEPT_FALSE throw(JPypeException) #endif #endif #include #include #include #include #include #include #include #include #include using std::map; using std::string; using std::stringstream; using std::cout; using std::cerr; using std::endl; using std::vector; using std::list; #ifdef JP_INSTRUMENTATION template constexpr uint32_t _hash(const char *q, uint32_t v) { return _hash < i - 1 > (q + 1, v * 0x1a481023 + q[0]); } template <> constexpr uint32_t _hash<0>(const char *q, uint32_t v) { return v; } #define compile_hash(x) _hash(x, 0) extern void PyJPModuleFault_throw(uint32_t code); extern int PyJPModuleFault_check(uint32_t code); #define JP_TRACE_IN(X, ...) try { PyJPModuleFault_throw(compile_hash(X)); #define JP_FAULT_RETURN(X, Y) if (PyJPModuleFault_check(compile_hash(X))) return Y #define JP_BLOCK(X) if (PyJPModuleFault_check(compile_hash(X))==0) #else #define JP_FAULT_RETURN(X, Y) if (false) while (false) #define JP_BLOCK(X) if (false) while (false) #endif /** Definition of commonly used template types */ typedef vector StringVector; /** * Converter are used for bulk byte transfers from Python to Java. */ typedef jvalue (*jconverter)(void*) ; /** * Create a converter for a bulk byte transfer. * * Bulk transfers do not check for range and may be lossy. These are only * triggered when a transfer either using memoryview or a slice operator * assignment from a buffer object (such as numpy.array). Converters are * created once at the start of the transfer and used to convert each * byte by casting the memory and then assigning to the jvalue union with * the requested type. * * Byte order transfers are not supported by the Python buffer API and thus * have not been implemented. * * @param from is a Python struct designation * @param itemsize is the size of the Python item * @param to is the desired Java primitive type * @return a converter function to convert each member. */ extern jconverter getConverter(const char* from, int itemsize, const char* to); extern bool _jp_cpp_exceptions; // Types class JPClass; class JPValue; class JPProxy; class JPArray; class JPArrayClass; class JPArrayView; class JPBoxedType; class JPPrimitiveType; class JPStringType; // Members class JPMethod; class JPMethodDispatch; class JPField; // Services class JPTypeManager; class JPClassLoader; class JPContext; class JPBuffer; class JPPyObject; extern "C" typedef void (*JCleanupHook)(void*) ; extern "C" struct JPConversionInfo; typedef vector JPClassList; typedef vector JPFieldList; typedef vector JPMethodDispatchList; typedef vector JPMethodList; class JPResource { public: virtual ~JPResource() = 0; } ; // Macros for raising an exception with jpype // These must be macros so that we can update the pattern and // maintain the appropriate auditing information. C++ does not // have a lot for facilities to make this easy. #define JP_RAISE_PYTHON() { throw JPypeException(JPError::_python_error, NULL, JP_STACKINFO()); } #define JP_RAISE_OS_ERROR_UNIX(err, msg) { throw JPypeException(JPError::_os_error_unix, msg, err, JP_STACKINFO()); } #define JP_RAISE_OS_ERROR_WINDOWS(err, msg) { throw JPypeException(JPError::_os_error_windows, msg, err, JP_STACKINFO()); } #define JP_RAISE_METHOD_NOT_FOUND(msg) { throw JPypeException(JPError::_method_not_found, NULL, msg, JP_STACKINFO()); } #define JP_RAISE(type, msg) { throw JPypeException(JPError::_python_exc, type, msg, JP_STACKINFO()); } #ifndef PyObject_HEAD struct _object; typedef _object PyObject; #endif // Base utility headers #include "jp_javaframe.h" #include "jp_context.h" #include "jp_exception.h" #include "jp_tracer.h" #include "jp_pythontypes.h" #include "jp_typemanager.h" #include "jp_encoding.h" #include "jp_modifier.h" #include "jp_match.h" // Other header files #include "jp_classhints.h" #include "jp_method.h" #include "jp_value.h" #include "jp_class.h" // Primitives classes #include "jp_primitivetype.h" #include "jp_typemanager.h" #endif // _JPYPE_H_jpype-1.3.0/native/common/jp_array.cpp000066400000000000000000000165721405671516700177620ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "pyjp.h" #include "jp_array.h" #include "jp_buffer.h" #include "jp_arrayclass.h" #include "jp_primitive_accessor.h" // Note: java represents arrays of zero length as null, thus we // need to be careful to handle these properly. We need to // carry them around so that we can match types. JPArray::JPArray(const JPValue &value) : m_Object(value.getClass()->getContext(), (jarray) value.getValue().l) { m_Class = (JPArrayClass*) value.getClass(); JPJavaFrame frame = JPJavaFrame::outer(m_Class->getContext()); JP_TRACE_IN("JPArray::JPArray"); ASSERT_NOT_NULL(m_Class); JP_TRACE(m_Class->toString()); // We will use this during range checks, so cache it if (m_Object.get() == NULL) m_Length = 0; // GCOVR_EXCL_LINE else m_Length = frame.GetArrayLength(m_Object.get()); m_Step = 1; m_Start = 0; m_Slice = false; JP_TRACE_OUT; } JPArray::JPArray(JPArray* instance, jsize start, jsize stop, jsize step) : m_Object(instance->m_Class->getContext(), (jarray) instance->getJava()) { JP_TRACE_IN("JPArray::JPArraySlice"); m_Class = instance->m_Class; m_Step = step * instance->m_Step; m_Start = instance->m_Start + instance->m_Step*start; if (step > 0) m_Length = (stop - start - 1 + step) / step; else m_Length = (stop - start + 1 + step) / step; if (m_Length < 0) m_Length = 0; // GCOVR_EXCL_LINE m_Slice = true; JP_TRACE_OUT; } JPArray::~JPArray() { } jsize JPArray::getLength() { return m_Length; } void JPArray::setRange(jsize start, jsize length, jsize step, PyObject* val) { JP_TRACE_IN("JPArray::setRange"); // Make sure it is an iterable before we start if (!PySequence_Check(val)) JP_RAISE(PyExc_TypeError, "can only assign a sequence"); JPJavaFrame frame = JPJavaFrame::outer(m_Class->getContext()); JPClass* compType = m_Class->getComponentType(); JPPySequence seq = JPPySequence::use(val); long plength = (long) seq.size(); JP_TRACE("Verify lengths", length, plength); if ((long) length != plength) { // Python would allow mismatching size by growing or shrinking // the length of the array. But java arrays are immutable in length. std::stringstream out; out << "Slice assignment must be of equal lengths : " << length << " != " << plength; JP_RAISE(PyExc_ValueError, out.str()); } JP_TRACE("Call component set range"); jsize i0 = m_Start + m_Step*start; compType->setArrayRange(frame, m_Object.get(), i0, length, m_Step*step, val); JP_TRACE_OUT; } void JPArray::setItem(jsize ndx, PyObject* val) { JPJavaFrame frame = JPJavaFrame::outer(m_Class->getContext()); JPClass* compType = m_Class->getComponentType(); if (ndx < 0) ndx += m_Length; if (ndx >= m_Length || ndx < 0) JP_RAISE(PyExc_IndexError, "java array assignment out of bounds"); compType->setArrayItem(frame, m_Object.get(), m_Start + ndx*m_Step, val); } JPPyObject JPArray::getItem(jsize ndx) { JPJavaFrame frame = JPJavaFrame::outer(m_Class->getContext()); JPClass* compType = m_Class->getComponentType(); if (ndx < 0) ndx += m_Length; if (ndx >= m_Length || ndx < 0) { JP_RAISE(PyExc_IndexError, "array index out of bounds"); } return compType->getArrayItem(frame, m_Object.get(), m_Start + ndx * m_Step); } jarray JPArray::clone(JPJavaFrame& frame, PyObject* obj) { JPValue value = m_Class->newArray(frame, m_Length); JPClass* compType = m_Class->getComponentType(); jarray out = (jarray) value.getValue().l; compType->setArrayRange(frame, out, 0, m_Length, 1, obj); return out; } JPArrayView::JPArrayView(JPArray* array) { JPJavaFrame frame = JPJavaFrame::outer(array->m_Class->getContext()); m_Array = array; m_RefCount = 0; m_Buffer.obj = NULL; m_Buffer.ndim = 1; m_Buffer.suboffsets = NULL; JPPrimitiveType *type = (JPPrimitiveType*) array->getClass()->getComponentType(); type->getView(*this); m_Strides[0] = m_Buffer.itemsize * array->m_Step; m_Shape[0] = array->m_Length; m_Buffer.buf = (char*) m_Memory + m_Buffer.itemsize * array->m_Start; m_Buffer.len = array->m_Length * m_Buffer.itemsize; m_Buffer.shape = m_Shape; m_Buffer.strides = m_Strides; m_Buffer.readonly = 1; m_Owned = false; } JPArrayView::JPArrayView(JPArray* array, jobject collection) { JP_TRACE_IN("JPArrayView::JPArrayView"); // All of the work has already been done by org.jpype.Utilities JPJavaFrame frame = JPJavaFrame::outer(array->m_Class->getContext()); m_Array = array; jint len = frame.GetArrayLength((jarray) collection); jobject item0 = frame.GetObjectArrayElement((jobjectArray) collection, 0); jobject item1 = frame.GetObjectArrayElement((jobjectArray) collection, 1); // First element is the primitive type that we are packing the array from JPPrimitiveType *componentType = (JPPrimitiveType*) frame.findClass((jclass) item0); // Second element is the shape of the array from which we compute the // memory size, the shape, and strides int dims; ssize_t itemsize; ssize_t sz; { JPPrimitiveArrayAccessor accessor(frame, (jintArray) item1, &JPJavaFrame::GetIntArrayElements, &JPJavaFrame::ReleaseIntArrayElements); jint* shape2 = accessor.get(); dims = frame.GetArrayLength((jarray) item1); itemsize = componentType->getItemSize(); sz = itemsize; for (int i = 0; i < dims; ++i) { m_Shape[i] = shape2[i]; sz *= m_Shape[i]; } accessor.abort(); } Py_ssize_t stride = itemsize; for (int i = 0; i < dims; ++i) { int n = dims - 1 - i; m_Strides[n] = stride; stride *= m_Shape[n]; } m_RefCount = 0; m_Memory = new char[sz]; m_Owned = true; // All remaining elements are primitive arrays to be unpacked int offset = 0; Py_ssize_t last = m_Shape[dims - 1]; for (Py_ssize_t i = 0; i < len - 2; i++) { jarray a1 = (jarray) frame.GetObjectArrayElement((jobjectArray) collection, (jsize) i + 2); componentType->copyElements(frame, a1, 0, (jsize) last, m_Memory, offset); offset += (int) (itemsize * last); frame.DeleteLocalRef(a1); } // Copy values into Python buffer for consumption m_Buffer.obj = NULL; m_Buffer.ndim = dims; m_Buffer.suboffsets = NULL; m_Buffer.itemsize = itemsize; m_Buffer.format = const_cast (componentType->getBufferFormat()); m_Buffer.buf = (char*) m_Memory + m_Buffer.itemsize * array->m_Start; m_Buffer.len = sz; m_Buffer.shape = m_Shape; m_Buffer.strides = m_Strides; m_Buffer.readonly = 1; JP_TRACE_OUT; // GCOVR_EXCL_LINE } JPArrayView::~JPArrayView() { if (m_Owned) delete [] (char*) m_Memory; } JPContext *JPArrayView::getContext() { return m_Array->getClass()->getContext(); } void JPArrayView::reference() { m_RefCount++; } bool JPArrayView::unreference() { m_RefCount--; JPPrimitiveType *type = (JPPrimitiveType*) m_Array->getClass()->getComponentType(); if (m_RefCount == 0 && !m_Owned) type->releaseView(*this); return m_RefCount == 0; } jpype-1.3.0/native/common/jp_arrayclass.cpp000066400000000000000000000056331405671516700210040ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "pyjp.h" #include "jp_arrayclass.h" #include "jp_context.h" #include "jp_stringtype.h" JPArrayClass::JPArrayClass(JPJavaFrame& frame, jclass cls, const string& name, JPClass* superClass, JPClass* componentType, jint modifiers) : JPClass(frame, cls, name, superClass, JPClassList(), modifiers) { m_ComponentType = componentType; } JPArrayClass::~JPArrayClass() { } JPMatch::Type JPArrayClass::findJavaConversion(JPMatch &match) { JP_TRACE_IN("JPArrayClass::findJavaConversion"); if (nullConversion->matches(this, match) || objectConversion->matches(this, match) || bufferConversion->matches(this, match) || charArrayConversion->matches(this, match) || byteArrayConversion->matches(this, match) || sequenceConversion->matches(this, match) ) return match.type; JP_TRACE("None"); return match.type = JPMatch::_none; JP_TRACE_OUT; } void JPArrayClass::getConversionInfo(JPConversionInfo &info) { JPJavaFrame frame = JPJavaFrame::outer(m_Context); objectConversion->getInfo(this, info); charArrayConversion->getInfo(this, info); byteArrayConversion->getInfo(this, info); sequenceConversion->getInfo(this, info); PyList_Append(info.ret, PyJPClass_create(frame, this).get()); } JPPyObject JPArrayClass::convertToPythonObject(JPJavaFrame& frame, jvalue value, bool cast) { JP_TRACE_IN("JPArrayClass::convertToPythonObject"); if (!cast) { if (value.l == NULL) return JPPyObject::getNone(); } JPPyObject wrapper = PyJPClass_create(frame, this); JPPyObject obj = PyJPArray_create(frame, (PyTypeObject*) wrapper.get(), JPValue(this, value)); return obj; JP_TRACE_OUT; } jvalue JPArrayClass::convertToJavaVector(JPJavaFrame& frame, JPPyObjectVector& refs, jsize start, jsize end) { JP_TRACE_IN("JPArrayClass::convertToJavaVector"); jsize length = (jsize) (end - start); jarray array = m_ComponentType->newArrayOf(frame, length); jvalue res; for (jsize i = start; i < end; i++) { m_ComponentType->setArrayItem(frame, array, i - start, refs[i]); } res.l = array; return res; JP_TRACE_OUT; } JPValue JPArrayClass::newArray(JPJavaFrame& frame, int length) { jvalue v; v.l = m_ComponentType->newArrayOf(frame, length); return JPValue(this, v); } jpype-1.3.0/native/common/jp_booleantype.cpp000066400000000000000000000235451405671516700211630ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "pyjp.h" #include "jp_array.h" #include "jp_primitive_accessor.h" #include "jp_booleantype.h" #include "jp_boxedtype.h" JPBooleanType::JPBooleanType() : JPPrimitiveType("boolean") { } JPBooleanType::~JPBooleanType() { } JPPyObject JPBooleanType::convertToPythonObject(JPJavaFrame& frame, jvalue val, bool cast) { return JPPyObject::call(PyBool_FromLong(val.z)); } JPValue JPBooleanType::getValueFromObject(const JPValue& obj) { JPContext *context = obj.getClass()->getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); jvalue v; field(v) = frame.CallBooleanMethodA(obj.getValue().l, context->_java_lang_Boolean->m_BooleanValueID, 0) != 0; return JPValue(this, v); } class JPConversionAsBoolean : public JPConversion { public: virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) override { if (!PyBool_Check(match.object)) return match.type = JPMatch::_none; match.conversion = this; return match.type = JPMatch::_exact; } virtual void getInfo(JPClass * cls, JPConversionInfo &info) override { PyList_Append(info.exact, (PyObject*) & PyBool_Type); } virtual jvalue convert(JPMatch &match) override { jvalue res; jlong v = PyObject_IsTrue(match.object); if (v == -1) JP_PY_CHECK(); res.z = v != 0; return res; } } asBooleanExact; class JPConversionAsBooleanJBool : public JPConversionJavaValue { public: virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) { JPValue *value = match.getJavaSlot(); if (value == NULL) return match.type = JPMatch::_none; match.type = JPMatch::_none; // Implied conversion from boxed to primitive (JLS 5.1.8) if (javaValueConversion->matches(cls, match) || unboxConversion->matches(cls, match)) return match.type; // Unboxing must be to the from the exact boxed type (JLS 5.1.8) return JPMatch::_implicit; // search no further. } void getInfo(JPClass *cls, JPConversionInfo &info) { JPContext *context = cls->getContext(); PyList_Append(info.exact, (PyObject*) context->_boolean->getHost()); unboxConversion->getInfo(cls, info); } } asBooleanJBool; class JPConversionAsBooleanLong : public JPConversionAsBoolean { public: virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) override { if (!PyLong_CheckExact(match.object) && !PyIndex_Check(match.object)) return match.type = JPMatch::_none; match.conversion = this; return match.type = JPMatch::_implicit; } virtual void getInfo(JPClass *cls, JPConversionInfo &info) override { PyObject *typing = PyImport_AddModule("jpype.protocol"); JPPyObject proto = JPPyObject::call(PyObject_GetAttrString(typing, "SupportsIndex")); PyList_Append(info.expl, proto.get()); } } asBooleanLong; class JPConversionAsBooleanNumber : public JPConversionAsBoolean { public: virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) override { if (!PyNumber_Check(match.object)) return match.type = JPMatch::_none; match.conversion = this; return match.type = JPMatch::_explicit; } virtual void getInfo(JPClass * cls, JPConversionInfo &info) override { PyObject *typing = PyImport_AddModule("jpype.protocol"); JPPyObject proto = JPPyObject::call(PyObject_GetAttrString(typing, "SupportsFloat")); PyList_Append(info.expl, proto.get()); } } asBooleanNumber; JPMatch::Type JPBooleanType::findJavaConversion(JPMatch &match) { JP_TRACE_IN("JPBooleanType::findJavaConversion", this); if (match.object == Py_None) return match.type = JPMatch::_none; if (asBooleanExact.matches(this, match) || asBooleanJBool.matches(this, match) || asBooleanLong.matches(this, match) || asBooleanNumber.matches(this, match) ) return match.type; return match.type = JPMatch::_none; JP_TRACE_OUT; } void JPBooleanType::getConversionInfo(JPConversionInfo &info) { JPJavaFrame frame = JPJavaFrame::outer(m_Context); asBooleanExact.getInfo(this, info); asBooleanJBool.getInfo(this, info); asBooleanLong.getInfo(this, info); asBooleanNumber.getInfo(this, info); PyList_Append(info.ret, (PyObject*) & PyBool_Type); } jarray JPBooleanType::newArrayOf(JPJavaFrame& frame, jsize sz) { return frame.NewBooleanArray(sz); } JPPyObject JPBooleanType::getStaticField(JPJavaFrame& frame, jclass c, jfieldID fid) { jvalue v; field(v) = frame.GetStaticBooleanField(c, fid); return convertToPythonObject(frame, v, false); } JPPyObject JPBooleanType::getField(JPJavaFrame& frame, jobject c, jfieldID fid) { jvalue v; field(v) = frame.GetBooleanField(c, fid); return convertToPythonObject(frame, v, false); } JPPyObject JPBooleanType::invokeStatic(JPJavaFrame& frame, jclass claz, jmethodID mth, jvalue* val) { jvalue v; { JPPyCallRelease call; field(v) = frame.CallStaticBooleanMethodA(claz, mth, val); } return convertToPythonObject(frame, v, false); } JPPyObject JPBooleanType::invoke(JPJavaFrame& frame, jobject obj, jclass clazz, jmethodID mth, jvalue* val) { jvalue v; { JPPyCallRelease call; if (clazz == NULL) field(v) = frame.CallBooleanMethodA(obj, mth, val); else field(v) = frame.CallNonvirtualBooleanMethodA(obj, clazz, mth, val); } return convertToPythonObject(frame, v, false); } void JPBooleanType::setStaticField(JPJavaFrame& frame, jclass c, jfieldID fid, PyObject* obj) { JPMatch match(&frame, obj); if (findJavaConversion(match) < JPMatch::_implicit) JP_RAISE(PyExc_TypeError, "Unable to convert to Java boolean"); type_t val = field(match.convert()); frame.SetStaticBooleanField(c, fid, val); } void JPBooleanType::setField(JPJavaFrame& frame, jobject c, jfieldID fid, PyObject* obj) { JPMatch match(&frame, obj); if (findJavaConversion(match) < JPMatch::_implicit) JP_RAISE(PyExc_TypeError, "Unable to convert to Java boolean"); type_t val = field(match.convert()); frame.SetBooleanField(c, fid, val); } void JPBooleanType::setArrayRange(JPJavaFrame& frame, jarray a, jsize start, jsize length, jsize step, PyObject* sequence) { JP_TRACE_IN("JPBooleanType::setArrayRange"); JPPrimitiveArrayAccessor accessor(frame, a, &JPJavaFrame::GetBooleanArrayElements, &JPJavaFrame::ReleaseBooleanArrayElements); type_t* val = accessor.get(); // First check if assigning sequence supports buffer API if (PyObject_CheckBuffer(sequence)) { JPPyBuffer buffer(sequence, PyBUF_FULL_RO); if (buffer.valid()) { Py_buffer& view = buffer.getView(); if (view.ndim != 1) JP_RAISE(PyExc_TypeError, "buffer dims incorrect"); Py_ssize_t vshape = view.shape[0]; Py_ssize_t vstep = view.strides[0]; if (vshape != length) JP_RAISE(PyExc_ValueError, "mismatched size"); char* memory = (char*) view.buf; if (view.suboffsets && view.suboffsets[0] >= 0) memory = *((char**) memory) + view.suboffsets[0]; jsize index = start; jconverter conv = getConverter(view.format, (int) view.itemsize, "z"); for (Py_ssize_t i = 0; i < length; ++i, index += step) { jvalue r = conv(memory); val[index] = r.z; memory += vstep; } accessor.commit(); return; } else { PyErr_Clear(); } } // Use sequence API JPPySequence seq = JPPySequence::use(sequence); jsize index = start; for (Py_ssize_t i = 0; i < length; ++i, index += step) { int v = PyObject_IsTrue(seq[i].get()); if (v == -1) JP_PY_CHECK(); val[index] = v; } accessor.commit(); JP_TRACE_OUT; } JPPyObject JPBooleanType::getArrayItem(JPJavaFrame& frame, jarray a, jsize ndx) { array_t array = (array_t) a; type_t val; frame.GetBooleanArrayRegion(array, ndx, 1, &val); jvalue v; field(v) = val; return convertToPythonObject(frame, v, false); } void JPBooleanType::setArrayItem(JPJavaFrame& frame, jarray a, jsize ndx, PyObject* obj) { JPMatch match(&frame, obj); if (findJavaConversion(match) < JPMatch::_implicit) JP_RAISE(PyExc_TypeError, "Unable to convert to Java boolean"); type_t val = field(match.convert()); frame.SetBooleanArrayRegion((array_t) a, ndx, 1, &val); } void JPBooleanType::getView(JPArrayView& view) { JPJavaFrame frame = JPJavaFrame::outer(view.getContext()); view.m_Memory = (void*) frame.GetBooleanArrayElements( (jbooleanArray) view.m_Array->getJava(), &view.m_IsCopy); view.m_Buffer.format = "?"; view.m_Buffer.itemsize = sizeof (jboolean); } void JPBooleanType::releaseView(JPArrayView& view) { try { JPJavaFrame frame = JPJavaFrame::outer(view.getContext()); frame.ReleaseBooleanArrayElements((jbooleanArray) view.m_Array->getJava(), (jboolean*) view.m_Memory, view.m_Buffer.readonly ? JNI_ABORT : 0); } catch (JPypeException&) { // This is called as part of the cleanup routine and exceptions // are not permitted } } const char* JPBooleanType::getBufferFormat() { return "?"; } ssize_t JPBooleanType::getItemSize() { return sizeof (jboolean); } void JPBooleanType::copyElements(JPJavaFrame &frame, jarray a, jsize start, jsize len, void* memory, int offset) { jboolean* b = (jboolean*) ((char*) memory + offset); frame.GetBooleanArrayRegion((jbooleanArray) a, start, len, b); } static void pack(jboolean* d, jvalue v) { *d = v.z; } PyObject *JPBooleanType::newMultiArray(JPJavaFrame &frame, JPPyBuffer &buffer, int subs, int base, jobject dims) { JP_TRACE_IN("JPBooleanType::newMultiArray"); return convertMultiArray( frame, this, &pack, "z", buffer, subs, base, dims); JP_TRACE_OUT; } jpype-1.3.0/native/common/jp_boxedtype.cpp000066400000000000000000000100541405671516700206340ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "pyjp.h" #include "jp_boxedtype.h" JPBoxedType::JPBoxedType(JPJavaFrame& frame, jclass clss, const string& name, JPClass* super, JPClassList& interfaces, jint modifiers, JPPrimitiveType* primitiveType) : JPClass(frame, clss, name, super, interfaces, modifiers), m_PrimitiveType(primitiveType) { if (name != "java.lang.Void") { string s = string("(") + primitiveType->getTypeCode() + ")V"; m_CtorID = frame.GetMethodID(clss, "", s.c_str()); } m_DoubleValueID = NULL; m_FloatValueID = NULL; m_LongValueID = NULL; m_IntValueID = NULL; m_BooleanValueID = NULL; m_CharValueID = NULL; if (name != "java.lang.Void" && name != "java.lang.Boolean" && name != "java.lang.Character" ) { m_DoubleValueID = frame.GetMethodID(clss, "doubleValue", "()D"); m_FloatValueID = frame.GetMethodID(clss, "floatValue", "()F"); m_IntValueID = frame.GetMethodID(clss, "intValue", "()I"); m_LongValueID = frame.GetMethodID(clss, "longValue", "()J"); } if (name == "java.lang.Boolean") { m_BooleanValueID = frame.GetMethodID(clss, "booleanValue", "()Z"); } if (name == "java.lang.Character") { m_CharValueID = frame.GetMethodID(clss, "charValue", "()C"); } } JPBoxedType::~JPBoxedType() { } JPMatch::Type JPBoxedType::findJavaConversion(JPMatch &match) { JP_TRACE_IN("JPBoxedType::findJavaConversion"); JPClass::findJavaConversion(match); if (match.type != JPMatch::_none) return match.type; if (m_PrimitiveType->findJavaConversion(match) != JPMatch::_none) { JP_TRACE("Primitive", match.type); match.conversion = boxBooleanConversion; match.closure = this; if (match.type == JPMatch::_exact) return match.type = JPMatch::_implicit; return match.type = JPMatch::_explicit; } return match.type = JPMatch::_none; JP_TRACE_OUT; } void JPBoxedType::getConversionInfo(JPConversionInfo &info) { JP_TRACE_IN("JPBoxedType::getConversionInfo"); JPJavaFrame frame = JPJavaFrame::outer(m_Context); m_PrimitiveType->getConversionInfo(info); JPPyObject::call(PyObject_CallMethod(info.expl, "extend", "O", info.implicit)); JPPyObject::call(PyObject_CallMethod(info.implicit, "clear", "")); JPPyObject::call(PyObject_CallMethod(info.implicit, "extend", "O", info.exact)); JPPyObject::call(PyObject_CallMethod(info.exact, "clear", "")); JPClass::getConversionInfo(info); JP_TRACE_OUT; } jobject JPBoxedType::box(JPJavaFrame &frame, jvalue v) { return frame.NewObjectA(m_Class.get(), m_CtorID, &v); } JPPyObject JPBoxedType::convertToPythonObject(JPJavaFrame& frame, jvalue value, bool cast) { JPClass *cls = this; if (!cast) { // This loses type if (value.l == NULL) { return JPPyObject::getNone(); } cls = frame.findClassForObject(value.l); if (cls != this) return cls->convertToPythonObject(frame, value, true); } JPPyObject wrapper = PyJPClass_create(frame, cls); JPPyObject obj; JPContext *context = frame.getContext(); if (this->getPrimitive() == context->_char) { jchar value2 = 0; // Not null get the char value if (value.l != 0) value2 = context->_char->getValueFromObject(JPValue(this, value)).getValue().c; // Create a char string object obj = JPPyObject::call(PyJPChar_Create((PyTypeObject*) wrapper.get(), value2)); } else obj = PyJPNumber_create(frame, wrapper, JPValue(cls, value)); PyJPValue_assignJavaSlot(frame, obj.get(), JPValue(cls, value)); return obj; } jpype-1.3.0/native/common/jp_buffer.cpp000066400000000000000000000035421405671516700201060ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "pyjp.h" #include "jp_buffer.h" #include "jp_primitive_accessor.h" #include "jp_buffertype.h" JPBuffer::JPBuffer(const JPValue &value) : m_Object(value.getClass()->getContext(), value.getValue().l) { m_Class = (JPBufferType*) value.getClass(); JPJavaFrame frame = JPJavaFrame::outer(m_Class->getContext()); JP_TRACE_IN("JPBuffer::JPBuffer"); m_Address = frame.GetDirectBufferAddress(m_Object.get()); m_Capacity = (Py_ssize_t) frame.GetDirectBufferCapacity(m_Object.get()); m_Buffer.buf = m_Address; m_Buffer.format = m_Format; m_Format[0] = frame.orderBuffer(m_Object.get()) ? '<' : '>'; m_Format[1] = m_Class->getType()[0]; m_Format[2] = 0; m_Buffer.itemsize = (Py_ssize_t) m_Class->getSize(); m_Buffer.ndim = 1; m_Buffer.readonly = frame.isBufferReadOnly(m_Object.get()); m_Buffer.shape = &m_Capacity; m_Buffer.strides = &m_Buffer.itemsize; m_Buffer.suboffsets = 0; JP_TRACE_OUT; // GCOVR_EXCL_LINE } JPBuffer::~JPBuffer() { } bool JPBuffer::isReadOnly() { return m_Buffer.readonly != 0; } Py_buffer& JPBuffer::getView() { return m_Buffer; } bool JPBuffer::isValid() { return m_Capacity != -1; } jpype-1.3.0/native/common/jp_buffertype.cpp000066400000000000000000000045131405671516700210070ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "pyjp.h" #include "jp_context.h" #include "jp_buffertype.h" JPBufferType::JPBufferType(JPJavaFrame& frame, jclass cls, const string& name, JPClass* superClass, const JPClassList& interfaces, jint modifiers) : JPClass(frame, cls, name, superClass, interfaces, modifiers) { // Use name to get the type if (name == "java.nio.Buffer") { m_Type = "b"; m_Size = 1; } else if (name == "java.nio.ByteBuffer") { m_Type = "b"; m_Size = 1; } else if (name == "java.nio.CharBuffer") { m_Type = "H"; m_Size = 2; } else if (name == "java.nio.ShortBuffer") { m_Type = "h"; m_Size = 2; } else if (name == "java.nio.IntBuffer") { m_Type = "i"; m_Size = 4; } else if (name == "java.nio.LongBuffer") { m_Type = "q"; m_Size = 8; } else if (name == "java.nio.FloatBuffer") { m_Type = "f"; m_Size = 4; } else if (name == "java.nio.DoubleBuffer") { m_Type = "d"; m_Size = 8; } else { JPBufferType* super = dynamic_cast (m_SuperClass); if (super == NULL) JP_RAISE(PyExc_TypeError, "Unsupported buffer type"); // GCOVR_EXCL_LINE m_Type = super->m_Type; m_Size = super->m_Size; } } JPBufferType::~JPBufferType() { } JPPyObject JPBufferType::convertToPythonObject(JPJavaFrame& frame, jvalue value, bool cast) { JP_TRACE_IN("JPBufferClass::convertToPythonObject"); if (!cast && value.l == NULL) return JPPyObject::getNone(); // GCOVR_EXCL_LINE JPPyObject wrapper = PyJPClass_create(frame, this); JPPyObject obj = PyJPBuffer_create(frame, (PyTypeObject*) wrapper.get(), JPValue(this, value)); return obj; JP_TRACE_OUT; // GCOVR_EXCL_LINE } jpype-1.3.0/native/common/jp_bytetype.cpp000066400000000000000000000205511405671516700205010ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "pyjp.h" #include "jp_array.h" #include "jp_primitive_accessor.h" #include "jp_bytetype.h" JPByteType::JPByteType() : JPPrimitiveType("byte") { } JPByteType::~JPByteType() { } JPPyObject JPByteType::convertToPythonObject(JPJavaFrame& frame, jvalue val, bool cast) { JPPyObject tmp = JPPyObject::call(PyLong_FromLong(field(val))); JPPyObject out = JPPyObject::call(convertLong(getHost(), (PyLongObject*) tmp.get())); PyJPValue_assignJavaSlot(frame, out.get(), JPValue(this, val)); return out; } JPValue JPByteType::getValueFromObject(const JPValue& obj) { JPContext *context = obj.getClass()->getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); jvalue v; jobject jo = obj.getValue().l; JPBoxedType* jb = (JPBoxedType*) frame.findClassForObject(jo); field(v) = (type_t) frame.CallIntMethodA(jo, jb->m_IntValueID, 0); return JPValue(this, v); } JPConversionLong byteConversion; JPConversionLongNumber byteNumberConversion; class JPConversionJByte : public JPConversionJavaValue { public: virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) { JPValue *value = match.getJavaSlot(); if (value == NULL) return match.type = JPMatch::_none; match.type = JPMatch::_none; // Implied conversion from boxed to primitive (JLS 5.1.8) if (javaValueConversion->matches(cls, match) || unboxConversion->matches(cls, match)) return match.type; // Unboxing must be to the from the exact boxed type (JLS 5.1.8) return JPMatch::_implicit; // stop the search } void getInfo(JPClass *cls, JPConversionInfo &info) { JPContext *context = cls->getContext(); PyList_Append(info.exact, (PyObject*) context->_byte->getHost()); unboxConversion->getInfo(cls, info); } } jbyteConversion; JPMatch::Type JPByteType::findJavaConversion(JPMatch &match) { JP_TRACE_IN("JPByteType::findJavaConversion"); if (match.object == Py_None) return match.type = JPMatch::_none; if (jbyteConversion.matches(this, match) || byteConversion.matches(this, match) || byteNumberConversion.matches(this, match)) return match.type; return match.type = JPMatch::_none; JP_TRACE_OUT; } void JPByteType::getConversionInfo(JPConversionInfo &info) { JPJavaFrame frame = JPJavaFrame::outer(m_Context); jbyteConversion.getInfo(this, info); byteConversion.getInfo(this, info); byteNumberConversion.getInfo(this, info); PyList_Append(info.ret, (PyObject*) m_Context->_int->getHost()); } jarray JPByteType::newArrayOf(JPJavaFrame& frame, jsize sz) { return frame.NewByteArray(sz); } JPPyObject JPByteType::getStaticField(JPJavaFrame& frame, jclass c, jfieldID fid) { jvalue v; field(v) = frame.GetStaticByteField(c, fid); return convertToPythonObject(frame, v, false); } JPPyObject JPByteType::getField(JPJavaFrame& frame, jobject c, jfieldID fid) { jvalue v; field(v) = frame.GetByteField(c, fid); return convertToPythonObject(frame, v, false); } JPPyObject JPByteType::invokeStatic(JPJavaFrame& frame, jclass claz, jmethodID mth, jvalue* val) { jvalue v; { JPPyCallRelease call; field(v) = frame.CallStaticByteMethodA(claz, mth, val); } return convertToPythonObject(frame, v, false); } JPPyObject JPByteType::invoke(JPJavaFrame& frame, jobject obj, jclass clazz, jmethodID mth, jvalue* val) { jvalue v; { JPPyCallRelease call; if (clazz == NULL) field(v) = frame.CallByteMethodA(obj, mth, val); else field(v) = frame.CallNonvirtualByteMethodA(obj, clazz, mth, val); } return convertToPythonObject(frame, v, false); } void JPByteType::setStaticField(JPJavaFrame& frame, jclass c, jfieldID fid, PyObject* obj) { JPMatch match(&frame, obj); if (findJavaConversion(match) < JPMatch::_implicit) JP_RAISE(PyExc_TypeError, "Unable to convert to Java byte"); type_t val = field(match.convert()); frame.SetStaticByteField(c, fid, val); } void JPByteType::setField(JPJavaFrame& frame, jobject c, jfieldID fid, PyObject* obj) { JPMatch match(&frame, obj); if (findJavaConversion(match) < JPMatch::_implicit) JP_RAISE(PyExc_TypeError, "Unable to convert to Java byte"); type_t val = field(match.convert()); frame.SetByteField(c, fid, val); } void JPByteType::setArrayRange(JPJavaFrame& frame, jarray a, jsize start, jsize length, jsize step, PyObject* sequence) { JP_TRACE_IN("JPByteType::setArrayRange"); JPPrimitiveArrayAccessor accessor(frame, a, &JPJavaFrame::GetByteArrayElements, &JPJavaFrame::ReleaseByteArrayElements); type_t* val = accessor.get(); // First check if assigning sequence supports buffer API if (PyObject_CheckBuffer(sequence)) { JPPyBuffer buffer(sequence, PyBUF_FULL_RO); if (buffer.valid()) { Py_buffer& view = buffer.getView(); if (view.ndim != 1) JP_RAISE(PyExc_TypeError, "buffer dims incorrect"); Py_ssize_t vshape = view.shape[0]; Py_ssize_t vstep = view.strides[0]; if (vshape != length) JP_RAISE(PyExc_ValueError, "mismatched size"); char* memory = (char*) view.buf; if (view.suboffsets && view.suboffsets[0] >= 0) memory = *((char**) memory) + view.suboffsets[0]; jsize index = start; jconverter conv = getConverter(view.format, (int) view.itemsize, "b"); for (Py_ssize_t i = 0; i < length; ++i, index += step) { jvalue r = conv(memory); val[index] = r.b; memory += vstep; } accessor.commit(); return; } else { PyErr_Clear(); } } // Use sequence API JPPySequence seq = JPPySequence::use(sequence); jsize index = start; for (Py_ssize_t i = 0; i < length; ++i, index += step) { PyObject *item = seq[i].get(); if (!PyIndex_Check(item)) { PyErr_Format(PyExc_TypeError, "Unable to implicitly convert '%s' to byte", Py_TYPE(item)->tp_name); JP_RAISE_PYTHON(); } jlong v = PyLong_AsLongLong(item); if (v == -1) JP_PY_CHECK(); val[index] = (type_t) assertRange(v); } accessor.commit(); JP_TRACE_OUT; } JPPyObject JPByteType::getArrayItem(JPJavaFrame& frame, jarray a, jsize ndx) { array_t array = (array_t) a; type_t val; frame.GetByteArrayRegion(array, ndx, 1, &val); jvalue v; field(v) = val; return convertToPythonObject(frame, v, false); } void JPByteType::setArrayItem(JPJavaFrame& frame, jarray a, jsize ndx, PyObject* obj) { JPMatch match(&frame, obj); if (findJavaConversion(match) < JPMatch::_implicit) JP_RAISE(PyExc_TypeError, "Unable to convert to Java byte"); type_t val = field(match.convert()); frame.SetByteArrayRegion((array_t) a, ndx, 1, &val); } void JPByteType::getView(JPArrayView& view) { JPJavaFrame frame = JPJavaFrame::outer(view.getContext()); view.m_Memory = (void*) frame.GetByteArrayElements( (jbyteArray) view.m_Array->getJava(), &view.m_IsCopy); view.m_Buffer.format = "b"; view.m_Buffer.itemsize = sizeof (jbyte); } void JPByteType::releaseView(JPArrayView& view) { try { JPJavaFrame frame = JPJavaFrame::outer(view.getContext()); frame.ReleaseByteArrayElements((jbyteArray) view.m_Array->getJava(), (jbyte*) view.m_Memory, view.m_Buffer.readonly ? JNI_ABORT : 0); } catch (JPypeException&) { // This is called as part of the cleanup routine and exceptions // are not permitted } } const char* JPByteType::getBufferFormat() { return "b"; } ssize_t JPByteType::getItemSize() { return sizeof (jbyte); } void JPByteType::copyElements(JPJavaFrame &frame, jarray a, jsize start, jsize len, void* memory, int offset) { jbyte* b = (jbyte*) ((char*) memory + offset); frame.GetByteArrayRegion((jbyteArray) a, start, len, b); } static void pack(jbyte* d, jvalue v) { *d = v.b; } PyObject *JPByteType::newMultiArray(JPJavaFrame &frame, JPPyBuffer &buffer, int subs, int base, jobject dims) { JP_TRACE_IN("JPByteType::newMultiArray"); return convertMultiArray( frame, this, &pack, "b", buffer, subs, base, dims); JP_TRACE_OUT; } jpype-1.3.0/native/common/jp_chartype.cpp000066400000000000000000000204441405671516700204540ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "pyjp.h" #include "jp_array.h" #include "jp_primitive_accessor.h" #include "jp_chartype.h" #include "jp_boxedtype.h" JPCharType::JPCharType() : JPPrimitiveType("char") { } JPCharType::~JPCharType() { } JPValue JPCharType::newInstance(JPJavaFrame& frame, JPPyObjectVector& args) { // This is only callable from one location so error checking is minimal if (args.size() != 1 || !PyIndex_Check(args[0])) JP_RAISE(PyExc_TypeError, "bad args"); // GCOVR_EXCL_LINE jvalue jv; // This is a cast so we must not fail int overflow; jv.c = PyLong_AsLongAndOverflow(args[0], &overflow); return JPValue(this, jv); } JPPyObject JPCharType::convertToPythonObject(JPJavaFrame& frame, jvalue val, bool cast) { // if (!cast) // { JPPyObject out = JPPyObject::call(PyJPChar_Create((PyTypeObject*) _JChar, val.c)); PyJPValue_assignJavaSlot(frame, out.get(), JPValue(this, val)); return out; // } // JPPyObject tmp = JPPyObject::call(PyLong_FromLong(field(val))); // JPPyObject out = JPPyObject::call(convertLong(getHost(), (PyLongObject*) tmp.get())); // return out; } JPValue JPCharType::getValueFromObject(const JPValue& obj) { JPContext *context = obj.getClass()->getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); jvalue v; field(v) = frame.CallCharMethodA(obj.getValue().l, context->_java_lang_Character->m_CharValueID, 0); return JPValue(this, v); } class JPConversionAsChar : public JPConversion { typedef JPCharType base_t; public: JPMatch::Type matches(JPClass *cls, JPMatch &match) override { JP_TRACE_IN("JPConversionAsChar::matches"); if (!JPPyString::checkCharUTF16(match.object)) return match.type = JPMatch::_none; match.conversion = this; return match.type = JPMatch::_implicit; JP_TRACE_OUT; // GCOVR_EXCL_LINE } virtual void getInfo(JPClass *cls, JPConversionInfo &info) override { PyList_Append(info.implicit, (PyObject*) & PyUnicode_Type); } virtual jvalue convert(JPMatch &match) override { jvalue res; res.c = JPPyString::asCharUTF16(match.object); return res; } } asCharConversion; class JPConversionAsJChar : public JPConversionJavaValue { public: virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) override { JPValue *value = match.getJavaSlot(); if (value == NULL) return match.type = JPMatch::_none; match.type = JPMatch::_none; // Exact // Implied conversion from boxed to primitive (JLS 5.1.8) if (javaValueConversion->matches(cls, match) || unboxConversion->matches(cls, match)) return match.type; // Unboxing must be to the from the exact boxed type (JLS 5.1.8) return JPMatch::_implicit; // stop search } virtual void getInfo(JPClass *cls, JPConversionInfo &info) override { JPContext *context = cls->getContext(); PyList_Append(info.exact, (PyObject*) context->_char->getHost()); unboxConversion->getInfo(cls, info); } } asJCharConversion; JPMatch::Type JPCharType::findJavaConversion(JPMatch &match) { JP_TRACE_IN("JPCharType::findJavaConversion"); if (match.object == Py_None) return match.type = JPMatch::_none; if (asJCharConversion.matches(this, match) || asCharConversion.matches(this, match)) return match.type; return match.type = JPMatch::_none; JP_TRACE_OUT; } void JPCharType::getConversionInfo(JPConversionInfo &info) { JPJavaFrame frame = JPJavaFrame::outer(m_Context); asJCharConversion.getInfo(this, info); asCharConversion.getInfo(this, info); PyList_Append(info.ret, (PyObject*) m_Context->_char->getHost()); } jarray JPCharType::newArrayOf(JPJavaFrame& frame, jsize sz) { return frame.NewCharArray(sz); } JPPyObject JPCharType::getStaticField(JPJavaFrame& frame, jclass c, jfieldID fid) { jvalue v; field(v) = frame.GetStaticCharField(c, fid); return convertToPythonObject(frame, v, false); } JPPyObject JPCharType::getField(JPJavaFrame& frame, jobject c, jfieldID fid) { jvalue v; field(v) = frame.GetCharField(c, fid); return convertToPythonObject(frame, v, false); } JPPyObject JPCharType::invokeStatic(JPJavaFrame& frame, jclass claz, jmethodID mth, jvalue* val) { jvalue v; { JPPyCallRelease call; field(v) = frame.CallStaticCharMethodA(claz, mth, val); } return convertToPythonObject(frame, v, false); } JPPyObject JPCharType::invoke(JPJavaFrame& frame, jobject obj, jclass clazz, jmethodID mth, jvalue* val) { jvalue v; { JPPyCallRelease call; if (clazz == NULL) field(v) = frame.CallCharMethodA(obj, mth, val); else field(v) = frame.CallNonvirtualCharMethodA(obj, clazz, mth, val); } return convertToPythonObject(frame, v, false); } void JPCharType::setStaticField(JPJavaFrame& frame, jclass c, jfieldID fid, PyObject* obj) { JPMatch match(&frame, obj); if (findJavaConversion(match) < JPMatch::_implicit) JP_RAISE(PyExc_TypeError, "Unable to convert to Java char"); type_t val = field(match.convert()); frame.SetStaticCharField(c, fid, val); } void JPCharType::setField(JPJavaFrame& frame, jobject c, jfieldID fid, PyObject* obj) { JPMatch match(&frame, obj); if (findJavaConversion(match) < JPMatch::_implicit) JP_RAISE(PyExc_TypeError, "Unable to convert to Java char"); type_t val = field(match.convert()); frame.SetCharField(c, fid, val); } void JPCharType::setArrayRange(JPJavaFrame& frame, jarray a, jsize start, jsize length, jsize step, PyObject* sequence) { JP_TRACE_IN("JPCharType::setArrayRange"); JPPrimitiveArrayAccessor accessor(frame, a, &JPJavaFrame::GetCharArrayElements, &JPJavaFrame::ReleaseCharArrayElements); type_t* val = accessor.get(); JPPySequence seq = JPPySequence::use(sequence); jsize index = start; for (Py_ssize_t i = 0; i < length; ++i, index += step) { jchar v = JPPyString::asCharUTF16(seq[i].get()); JP_PY_CHECK(); val[index] = (type_t) v; } accessor.commit(); JP_TRACE_OUT; } JPPyObject JPCharType::getArrayItem(JPJavaFrame& frame, jarray a, jsize ndx) { array_t array = (array_t) a; type_t val; frame.GetCharArrayRegion(array, ndx, 1, &val); jvalue v; field(v) = val; return convertToPythonObject(frame, v, false); } void JPCharType::setArrayItem(JPJavaFrame& frame, jarray a, jsize ndx, PyObject* obj) { JPMatch match(&frame, obj); if (findJavaConversion(match) < JPMatch::_implicit) JP_RAISE(PyExc_TypeError, "Unable to convert to Java char"); type_t val = field(match.convert()); frame.SetCharArrayRegion((array_t) a, ndx, 1, &val); } void JPCharType::getView(JPArrayView& view) { JPJavaFrame frame = JPJavaFrame::outer(view.getContext()); view.m_Memory = (void*) frame.GetCharArrayElements( (jcharArray) view.m_Array->getJava(), &view.m_IsCopy); view.m_Buffer.format = "H"; view.m_Buffer.itemsize = sizeof (jchar); } void JPCharType::releaseView(JPArrayView& view) { try { JPJavaFrame frame = JPJavaFrame::outer(view.getContext()); frame.ReleaseCharArrayElements((jcharArray) view.m_Array->getJava(), (jchar*) view.m_Memory, view.m_Buffer.readonly ? JNI_ABORT : 0); } catch (JPypeException&) { // This is called as part of the cleanup routine and exceptions // are not permitted } } const char* JPCharType::getBufferFormat() { return "H"; } ssize_t JPCharType::getItemSize() { return sizeof (jchar); } void JPCharType::copyElements(JPJavaFrame &frame, jarray a, jsize start, jsize len, void* memory, int offset) { jchar* b = (jchar*) ((char*) memory + offset); frame.GetCharArrayRegion((jcharArray) a, start, len, b); } static void pack(jchar* d, jvalue v) { *d = v.c; } PyObject *JPCharType::newMultiArray(JPJavaFrame &frame, JPPyBuffer &buffer, int subs, int base, jobject dims) { JP_TRACE_IN("JPCharType::newMultiArray"); return convertMultiArray( frame, this, &pack, "c", buffer, subs, base, dims); JP_TRACE_OUT; } jpype-1.3.0/native/common/jp_class.cpp000066400000000000000000000264351405671516700177500ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "pyjp.h" #include "jp_field.h" #include "jp_methoddispatch.h" #include "jp_method.h" JPClass::JPClass( const string& name, jint modifiers) { m_Context = NULL; m_CanonicalName = name; m_SuperClass = NULL; m_Interfaces = JPClassList(); m_Modifiers = modifiers; } JPClass::JPClass(JPJavaFrame& frame, jclass clss, const string& name, JPClass* super, const JPClassList& interfaces, jint modifiers) : m_Class(frame, clss) { m_Context = frame.getContext(); m_CanonicalName = name; m_SuperClass = super; m_Interfaces = interfaces; m_Modifiers = modifiers; } JPClass::~JPClass() { } void JPClass::setHost(PyObject* host) { m_Host = JPPyObject::use(host); } void JPClass::setHints(PyObject* host) { m_Hints = JPPyObject::use(host); } jclass JPClass::getJavaClass() const { jclass cls = m_Class.get(); // This sanity check should not be possible to exercise if (cls == 0) JP_RAISE(PyExc_RuntimeError, "Class is null"); // GCOVR_EXCL_LINE return cls; } void JPClass::ensureMembers(JPJavaFrame& frame) { JPContext* context = frame.getContext(); JPTypeManager* typeManager = context->getTypeManager(); typeManager->populateMembers(this); } void JPClass::assignMembers(JPMethodDispatch* ctor, JPMethodDispatchList& methods, JPFieldList& fields) { m_Constructors = ctor; m_Methods = methods; m_Fields = fields; } // JPValue JPClass::newInstance(JPJavaFrame& frame, JPPyObjectVector& args) { if (m_Constructors == NULL) { if (this->isInterface()) { JP_RAISE(PyExc_TypeError, "Cannot create Java interface instances"); } else { JP_RAISE(PyExc_TypeError, "Java class has no constructors"); } } return m_Constructors->invokeConstructor(frame, args); } JPContext* JPClass::getContext() const { // This sanity check is for during shutdown. if (m_Context == 0) JP_RAISE(PyExc_RuntimeError, "Null context"); // GCOVR_EXCL_LINE return m_Context; } JPClass* JPClass::newArrayType(JPJavaFrame &frame, long d) { if (d < 0 || d > 255) JP_RAISE(PyExc_ValueError, "Invalid array dimensions"); stringstream ss; for (long i = 0; i < d; ++i) ss << "["; if (isPrimitive()) ss << ((JPPrimitiveType*) this)->getTypeCode(); else if (isArray()) ss << getName(); else ss << "L" << getName() << ";"; return frame.findClassByName(ss.str()); } jarray JPClass::newArrayOf(JPJavaFrame& frame, jsize sz) { return frame.NewObjectArray(sz, getJavaClass(), NULL); } // // // GCOVR_EXCL_START // This is currently only used in tracing string JPClass::toString() const { // This sanity check will not be hit in normal operation if (m_Context == 0) return m_CanonicalName; // GCOVR_EXCL_LINE JPJavaFrame frame = JPJavaFrame::outer(m_Context); return frame.toString(m_Class.get()); } // GCOVR_EXCL_STOP string JPClass::getName() const { // This sanity check will not be hit in normal operation if (m_Context == 0) return m_CanonicalName; // GCOVR_EXCL_LINE JPJavaFrame frame = JPJavaFrame::outer(m_Context); return frame.toString(frame.CallObjectMethodA( (jobject) m_Class.get(), m_Context->m_Class_GetNameID, NULL)); } // // JPPyObject JPClass::getStaticField(JPJavaFrame& frame, jclass c, jfieldID fid) { JP_TRACE_IN("JPClass::getStaticField"); jobject r = frame.GetStaticObjectField(c, fid); JPClass* type = this; if (r != NULL) type = frame.findClassForObject(r); jvalue v; v.l = r; return type->convertToPythonObject(frame, v, false); JP_TRACE_OUT; } JPPyObject JPClass::getField(JPJavaFrame& frame, jobject c, jfieldID fid) { JP_TRACE_IN("JPClass::getField"); jobject r = frame.GetObjectField(c, fid); JPClass* type = this; if (r != NULL) type = frame.findClassForObject(r); jvalue v; v.l = r; return type->convertToPythonObject(frame, v, false); JP_TRACE_OUT; } JPPyObject JPClass::invokeStatic(JPJavaFrame& frame, jclass claz, jmethodID mth, jvalue* val) { JP_TRACE_IN("JPClass::invokeStatic"); jvalue v; { JPPyCallRelease call; v.l = frame.CallStaticObjectMethodA(claz, mth, val); } JPClass *type = this; if (v.l != NULL) type = frame.findClassForObject(v.l); return type->convertToPythonObject(frame, v, false); JP_TRACE_OUT; } JPPyObject JPClass::invoke(JPJavaFrame& frame, jobject obj, jclass clazz, jmethodID mth, jvalue* val) { JP_TRACE_IN("JPClass::invoke"); jvalue v; // Call method { JPPyCallRelease call; if (obj == NULL) JP_RAISE(PyExc_ValueError, "method called on null object"); if (clazz == NULL) v.l = frame.CallObjectMethodA(obj, mth, val); else v.l = frame.CallNonvirtualObjectMethodA(obj, clazz, mth, val); } // Get the return type JPClass *type = this; if (v.l != NULL) type = frame.findClassForObject(v.l); return type->convertToPythonObject(frame, v, false); JP_TRACE_OUT; } void JPClass::setStaticField(JPJavaFrame& frame, jclass c, jfieldID fid, PyObject* obj) { JP_TRACE_IN("JPClass::setStaticField"); JPMatch match(&frame, obj); if (findJavaConversion(match) < JPMatch::_implicit) { stringstream err; err << "unable to convert to " << getCanonicalName(); JP_RAISE(PyExc_TypeError, err.str().c_str()); } jobject val = match.convert().l; frame.SetStaticObjectField(c, fid, val); JP_TRACE_OUT; } void JPClass::setField(JPJavaFrame& frame, jobject c, jfieldID fid, PyObject* obj) { JP_TRACE_IN("JPClass::setField"); JPMatch match(&frame, obj); if (findJavaConversion(match) < JPMatch::_implicit) { stringstream err; err << "unable to convert to " << getCanonicalName(); JP_RAISE(PyExc_TypeError, err.str().c_str()); } jobject val = match.convert().l; frame.SetObjectField(c, fid, val); JP_TRACE_OUT; } void JPClass::setArrayRange(JPJavaFrame& frame, jarray a, jsize start, jsize length, jsize step, PyObject* vals) { JP_TRACE_IN("JPClass::setArrayRange"); jobjectArray array = (jobjectArray) a; // Verify before we start the conversion, as we wont be able // to abort once we start JPPySequence seq = JPPySequence::use(vals); JP_TRACE("Verify argument types"); for (int i = 0; i < length; i++) { JPPyObject v = seq[i]; JPMatch match(&frame, v.get()); if (findJavaConversion(match) < JPMatch::_implicit) JP_RAISE(PyExc_TypeError, "Unable to convert"); } JP_TRACE("Copy"); int index = start; for (int i = 0; i < length; i++, index += step) { JPPyObject v = seq[i]; JPMatch match(&frame, v.get()); findJavaConversion(match); frame.SetObjectArrayElement(array, index, match.convert().l); } JP_TRACE_OUT; } void JPClass::setArrayItem(JPJavaFrame& frame, jarray a, jsize ndx, PyObject* val) { JP_TRACE_IN("JPClass::setArrayItem"); JPMatch match(&frame, val); findJavaConversion(match); JP_TRACE("Type", getCanonicalName()); if ( match.type < JPMatch::_implicit) { JP_RAISE(PyExc_TypeError, "Unable to convert"); } jvalue v = match.convert(); frame.SetObjectArrayElement((jobjectArray) a, ndx, v.l); JP_TRACE_OUT; } JPPyObject JPClass::getArrayItem(JPJavaFrame& frame, jarray a, jsize ndx) { JP_TRACE_IN("JPClass::getArrayItem"); jobjectArray array = (jobjectArray) a; jobject obj = frame.GetObjectArrayElement(array, ndx); JPClass *retType = this; jvalue v; v.l = obj; if (obj != NULL) retType = frame.findClassForObject(v.l); return retType->convertToPythonObject(frame, v, false); JP_TRACE_OUT; } // // JPValue JPClass::getValueFromObject(const JPValue& obj) { JP_TRACE_IN("JPClass::getValueFromObject"); return JPValue(this, obj.getJavaObject()); JP_TRACE_OUT; } JPPyObject JPClass::convertToPythonObject(JPJavaFrame& frame, jvalue value, bool cast) { JP_TRACE_IN("JPClass::convertToPythonObject"); JPClass *cls = this; if (!cast) { // Returning None likely incorrect from java prospective. // Java still knows the type of null objects thus // converting to None would pose a problem as we lose type. // We would need subclass None for this to make sense so we // can carry both the type and the null, but Python considers // None a singleton so this is not an option. // // Of course if we don't mind that "Object is None" would // fail, but "Object == None" would be true, the we // could support null objects properly. However, this would // need to work as "None == Object" which may be hard to // achieve. // // We will still need to have the concept of null objects // but we can get those through JObject(None, cls). if (value.l == NULL) { return JPPyObject::getNone(); } cls = frame.findClassForObject(value.l); if (cls != this) return cls->convertToPythonObject(frame, value, true); } JPPyObject obj; JPPyObject wrapper = PyJPClass_create(frame, cls); if (isThrowable()) { JPPyObject tuple0; if (value.l == NULL) { tuple0 = JPPyObject::call(PyTuple_New(0)); } else { jstring m = frame.getMessage((jthrowable) value.l); if (m != NULL) { tuple0 = JPPyObject::call(PyTuple_Pack(1, JPPyString::fromStringUTF8(frame.toStringUTF8(m)).get())); } else { tuple0 = JPPyObject::call(PyTuple_Pack(1, JPPyString::fromStringUTF8(frame.toString(value.l)).get())); } } JPPyObject tuple1 = JPPyObject::call(PyTuple_Pack(2, _JObjectKey, tuple0.get())); // Exceptions need new and init obj = JPPyObject::call(PyObject_Call(wrapper.get(), tuple1.get(), NULL)); } else { PyTypeObject *type = ((PyTypeObject*) wrapper.get()); // Simple objects don't have a new or init function PyObject *obj2 = type->tp_alloc(type, 0); JP_PY_CHECK(); obj = JPPyObject::claim(obj2); } // Fill in the Java slot PyJPValue_assignJavaSlot(frame, obj.get(), JPValue(cls, value)); return obj; JP_TRACE_OUT; } JPMatch::Type JPClass::findJavaConversion(JPMatch &match) { JP_TRACE_IN("JPClass::findJavaConversion"); if (nullConversion->matches(this, match) || objectConversion->matches(this, match) || proxyConversion->matches(this, match) || hintsConversion->matches(this, match)) return match.type; JP_TRACE("No match"); return match.type = JPMatch::_none; JP_TRACE_OUT; } void JPClass::getConversionInfo(JPConversionInfo &info) { JP_TRACE_IN("JPClass::getConversionInfo"); JPJavaFrame frame = JPJavaFrame::outer(m_Context); objectConversion->getInfo(this, info); hintsConversion->getInfo(this, info); PyList_Append(info.ret, PyJPClass_create(frame, this).get()); JP_TRACE_OUT; } // // bool JPClass::isAssignableFrom(JPJavaFrame& frame, JPClass* o) { return frame.IsAssignableFrom(m_Class.get(), o->getJavaClass()) != 0; } // jpype-1.3.0/native/common/jp_classhints.cpp000066400000000000000000000672461405671516700210230ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include #include "jpype.h" #include "jp_classhints.h" #include "jp_arrayclass.h" #include "jp_stringtype.h" #include "jp_proxy.h" #include "pyjp.h" JPMatch::JPMatch() { conversion = NULL; frame = NULL; object = NULL; type = JPMatch::_none; slot = (JPValue*) - 1; closure = 0; } JPMatch::JPMatch(JPJavaFrame *fr, PyObject *obj) { conversion = NULL; frame = fr; object = obj; type = JPMatch::_none; slot = (JPValue*) - 1; closure = 0; } JPValue *JPMatch::getJavaSlot() { if (slot == (JPValue*) - 1) return slot = PyJPValue_getJavaSlot(object); return slot; } jvalue JPMatch::convert() { // Sanity check, this should not happen if (conversion == NULL) JP_RAISE(PyExc_SystemError, "Fail in conversion"); // GCOVR_EXCL_LINE return conversion->convert(*this); } JPMethodMatch::JPMethodMatch(JPJavaFrame &frame, JPPyObjectVector& args, bool callInstance) : m_Arguments(args.size()) { m_Type = JPMatch::_none; m_IsVarIndirect = false; m_Overload = 0; m_Offset = 0; m_Skip = 0; m_Hash = callInstance ? 0 : 1000; for (size_t i = 0; i < args.size(); ++i) { PyObject *arg = args[i]; m_Arguments[i] = JPMatch(&frame, arg); // This is an LCG used to compute a hash code for the incoming // arguments using (A*X+A_i) mod2^64 where A_i is the address of each // type the argument list. The hash will be checked to avoid needing // to resolve the method if the same overload is called twice. There // is only a speed cost if there is a collision, so we don't need to // prove this is a perfect hash function. m_Hash *= 0x10523C01; m_Hash += (long) (Py_TYPE(arg)); } } JPConversion::~JPConversion() { } JPClassHints::JPClassHints() { } JPClassHints::~JPClassHints() { for (std::list::iterator iter = conversions.begin(); iter != conversions.end(); ++iter) { delete *iter; } conversions.clear(); } JPMatch::Type JPClassHints::getConversion(JPMatch& match, JPClass *cls) { JPConversion *best = NULL; for (std::list::iterator iter = conversions.begin(); iter != conversions.end(); ++iter) { JPMatch::Type quality = (*iter)->matches(cls, match); if (quality > JPMatch::_explicit) return match.type; if (quality != JPMatch::_none) best = (*iter); } match.conversion = best; if (best == NULL) return match.type = JPMatch::_none; return match.type = JPMatch::_explicit; } void JPIndexConversion::getInfo(JPClass *cls, JPConversionInfo &info) { PyObject *typing = PyImport_AddModule("jpype.protocol"); JPPyObject proto = JPPyObject::call(PyObject_GetAttrString(typing, "SupportsIndex")); PyList_Append(info.implicit, proto.get()); } void JPNumberConversion::getInfo(JPClass *cls, JPConversionInfo &info) { JPIndexConversion::getInfo(cls, info); PyObject *typing = PyImport_AddModule("jpype.protocol"); JPPyObject proto = JPPyObject::call(PyObject_GetAttrString(typing, "SupportsFloat")); PyList_Append(info.implicit, proto.get()); } /** * Conversion for all user specified conversions. */ class JPPythonConversion : public JPConversion { public: JPPythonConversion(PyObject *method) { method_ = JPPyObject::use(method); } virtual ~JPPythonConversion() // GCOVR_EXCL_LINE { } virtual jvalue convert(JPMatch &match) override { JP_TRACE_IN("JPPythonConversion::convert"); JPClass *cls = ((JPClass*) match.closure); JPPyObject args = JPPyObject::call(PyTuple_Pack(2, cls->getHost(), match.object)); JPPyObject ret = JPPyObject::call(PyObject_Call(method_.get(), args.get(), NULL)); JPValue *value = PyJPValue_getJavaSlot(ret.get()); if (value != NULL) { jvalue v = value->getValue(); JP_TRACE("Value", v.l); v.l = match.frame->NewLocalRef(v.l); return v; } JPProxy *proxy = PyJPProxy_getJPProxy(ret.get()); if (proxy != NULL) { jvalue v = proxy->getProxy(); JP_TRACE("Proxy", v.l); v.l = match.frame->NewLocalRef(v.l); return v; } JP_RAISE(PyExc_TypeError, "Bad type conversion"); JP_TRACE_OUT; } private: JPPyObject method_; } ; // class JPAttributeConversion : public JPPythonConversion { public: JPAttributeConversion(const string &attribute, PyObject *method) : JPPythonConversion(method), attribute_(attribute) { } virtual ~JPAttributeConversion() // GCOVR_EXCL_LINE { } virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) override { JP_TRACE_IN("JPAttributeConversion::matches"); JPPyObject attr = JPPyObject::accept(PyObject_GetAttrString(match.object, attribute_.c_str())); if (attr.isNull()) return JPMatch::_none; match.conversion = this; match.closure = cls; return match.type = JPMatch::_implicit; JP_TRACE_OUT; } virtual void getInfo(JPClass *cls, JPConversionInfo &info) override { PyList_Append(info.attributes, JPPyString::fromStringUTF8(attribute_).get()); } private: std::string attribute_; } ; void JPClassHints::addAttributeConversion(const string &attribute, PyObject *conversion) { JP_TRACE_IN("JPClassHints::addAttributeConversion", this); JP_TRACE(attribute); conversions.push_back(new JPAttributeConversion(attribute, conversion)); JP_TRACE_OUT; } // // class JPNoneConversion : public JPConversion { public: JPNoneConversion(PyObject *type) { type_ = JPPyObject::use(type); } virtual ~JPNoneConversion() { } virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) override { JP_TRACE_IN("JPTypeConversion::matches"); if (!PyObject_IsInstance(match.object, type_.get())) return JPMatch::_none; match.closure = cls; match.conversion = this; match.type = JPMatch::_none; return JPMatch::_implicit; // Prevent further searching JP_TRACE_OUT; } virtual void getInfo(JPClass *cls, JPConversionInfo &info) override { PyList_Append(info.none, type_.get()); } virtual jvalue convert(JPMatch &match) override { return jvalue(); } private: JPPyObject type_; } ; class JPTypeConversion : public JPPythonConversion { public: JPTypeConversion(PyObject *type, PyObject *method, bool exact) : JPPythonConversion(method), exact_(exact) { type_ = JPPyObject::use(type); } virtual ~JPTypeConversion() { } virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) override { JP_TRACE_IN("JPTypeConversion::matches"); if ((exact_ && ((PyObject*) Py_TYPE(match.object)) == type_.get()) || PyObject_IsInstance(match.object, type_.get())) { match.closure = cls; match.conversion = this; return match.type = JPMatch::_implicit; } return JPMatch::_none; JP_TRACE_OUT; } virtual void getInfo(JPClass *cls, JPConversionInfo &info) override { PyList_Append(info.implicit, type_.get()); } private: JPPyObject type_; bool exact_; } ; void JPClassHints::addTypeConversion(PyObject *type, PyObject *method, bool exact) { JP_TRACE_IN("JPClassHints::addTypeConversion", this); conversions.push_back(new JPTypeConversion(type, method, exact)); JP_TRACE_OUT; } void JPClassHints::excludeConversion(PyObject *type) { JP_TRACE_IN("JPClassHints::addTypeConversion", this); conversions.push_front(new JPNoneConversion(type)); JP_TRACE_OUT; } void JPClassHints::getInfo(JPClass *cls, JPConversionInfo &info) { for (std::list::iterator iter = conversions.begin(); iter != conversions.end(); ++iter) { (*iter)->getInfo(cls, info); } } class JPHintsConversion : public JPConversion { public: virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) override { PyJPClassHints *pyhints = (PyJPClassHints*) cls->getHints(); // GCOVR_EXCL_START if (pyhints == NULL) { // Force creation of the class that will create the hints PyJPClass_create(*match.frame, cls); pyhints = (PyJPClassHints*) cls->getHints(); if (pyhints == NULL) return match.type = JPMatch::_none; } // GCOVR_EXCL_STOP JPClassHints *hints = pyhints->m_Hints; hints->getConversion(match, cls); return match.type; } virtual void getInfo(JPClass *cls, JPConversionInfo &info) override { PyJPClassHints *pyhints = (PyJPClassHints*) cls->getHints(); if (pyhints == NULL) return; JPClassHints *hints = pyhints->m_Hints; hints->getInfo(cls, info); } virtual jvalue convert(JPMatch &match) override { return jvalue(); } } _hintsConversion; // class JPConversionCharArray : public JPConversion { public: virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) override { JP_TRACE_IN("JPConversionCharArray::matches"); JPArrayClass* acls = (JPArrayClass*) cls; if (match.frame == NULL || !JPPyString::check(match.object) || acls->getComponentType() != match.getContext()->_char) return match.type = JPMatch::_none; match.conversion = this; return match.type = JPMatch::_implicit; JP_TRACE_OUT; } virtual void getInfo(JPClass *cls, JPConversionInfo &info) override { JPArrayClass* acls = (JPArrayClass*) cls; if (acls->getComponentType() != cls->getContext()->_char) return; PyList_Append(info.implicit, (PyObject*) & PyUnicode_Type); } virtual jvalue convert(JPMatch &match) override { JPJavaFrame *frame = match.frame; JP_TRACE("char[]"); jvalue res; // Convert to a string string str = JPPyString::asStringUTF8(match.object); // Convert to new java string jstring jstr = frame->fromStringUTF8(str); // call toCharArray() res.l = frame->toCharArray(jstr); return res; } } _charArrayConversion; class JPConversionByteArray : public JPConversion { public: virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) override { JP_TRACE_IN("JPConversionByteArray::matches"); JPArrayClass* acls = (JPArrayClass*) cls; if (match.frame == NULL || !PyBytes_Check(match.object) || acls->getComponentType() != match.frame->getContext()->_byte) return match.type = JPMatch::_none; match.conversion = this; return match.type = JPMatch::_implicit; JP_TRACE_OUT; } virtual void getInfo(JPClass *cls, JPConversionInfo &info) override { JPArrayClass* acls = (JPArrayClass*) cls; if (acls->getComponentType() != cls->getContext()->_byte) return; PyList_Append(info.implicit, (PyObject*) & PyBytes_Type); } virtual jvalue convert(JPMatch &match) override { JPJavaFrame frame(*match.frame); jvalue res; Py_ssize_t size = 0; char *buffer = NULL; PyBytes_AsStringAndSize(match.object, &buffer, &size); // internal reference jbyteArray byteArray = frame.NewByteArray((jsize) size); frame.SetByteArrayRegion(byteArray, 0, (jsize) size, (jbyte*) buffer); res.l = frame.keep(byteArray); return res; } } _byteArrayConversion; class JPConversionBuffer : public JPConversion { public: virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) override { JP_TRACE_IN("JPConversionBuffer::matches"); JPArrayClass *acls = (JPArrayClass*) cls; JPClass *componentType = acls->getComponentType(); if ( !componentType->isPrimitive()) return match.type = JPMatch::_none; // If is isn't a buffer we can skip JPPyBuffer buffer(match.object, PyBUF_ND | PyBUF_FORMAT); if (!buffer.valid()) { PyErr_Clear(); return match.type = JPMatch::_none; } // If it is a buffer we only need to test the first item in the list JPPySequence seq = JPPySequence::use(match.object); jlong length = seq.size(); match.type = JPMatch::_implicit; if (length > 0) { JPPyObject item = seq[0]; JPMatch imatch(match.frame, item.get()); componentType->findJavaConversion(imatch); if (imatch.type < match.type) match.type = imatch.type; } match.closure = cls; match.conversion = bufferConversion; return match.type; JP_TRACE_OUT; } virtual void getInfo(JPClass *cls, JPConversionInfo &info) override { // This will be covered by Sequence } virtual jvalue convert(JPMatch &match) override { JPJavaFrame frame(*match.frame); jvalue res; JPArrayClass *acls = (JPArrayClass *) match.closure; jsize length = (jsize) PySequence_Length(match.object); JPClass *ccls = acls->getComponentType(); jarray array = ccls->newArrayOf(frame, (jsize) length); ccls->setArrayRange(frame, array, 0, length, 1, match.object); res.l = frame.keep(array); return res; } } _bufferConversion; class JPConversionSequence : public JPConversion { public: virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) override { JP_TRACE_IN("JPConversionSequence::matches"); if ( !PySequence_Check(match.object) || JPPyString::check(match.object)) return match.type = JPMatch::_none; JPArrayClass *acls = (JPArrayClass*) cls; JPClass *componentType = acls->getComponentType(); JPPySequence seq = JPPySequence::use(match.object); jlong length = seq.size(); match.type = JPMatch::_implicit; for (jlong i = 0; i < length && match.type > JPMatch::_none; i++) { // This is a special case. Sequences produce new references // so we must hold the reference in a container while the // the match is caching it. JPPyObject item = seq[i]; JPMatch imatch(match.frame, item.get()); componentType->findJavaConversion(imatch); if (imatch.type < match.type) match.type = imatch.type; } match.closure = cls; match.conversion = sequenceConversion; return match.type; JP_TRACE_OUT; } virtual void getInfo(JPClass *cls, JPConversionInfo &info) override { PyObject *typing = PyImport_AddModule("jpype.protocol"); JPPyObject proto = JPPyObject::call(PyObject_GetAttrString(typing, "Sequence")); PyList_Append(info.implicit, proto.get()); JPArrayClass* acls = (JPArrayClass*) cls; if (acls->getComponentType() == cls->getContext()->_char) return; PyList_Append(info.none, (PyObject*) & PyUnicode_Type); } virtual jvalue convert(JPMatch &match) override { JPJavaFrame frame(*match.frame); jvalue res; JPArrayClass *acls = (JPArrayClass *) match.closure; jsize length = (jsize) PySequence_Length(match.object); JPClass *ccls = acls->getComponentType(); jarray array = ccls->newArrayOf(frame, (jsize) length); ccls->setArrayRange(frame, array, 0, length, 1, match.object); res.l = frame.keep(array); return res; } } _sequenceConversion; class JPConversionNull : public JPConversion { public: virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) override { JP_TRACE_IN("JPConversionNull::matches"); if (match.object != Py_None) return match.type = JPMatch::_none; match.conversion = this; return match.type = JPMatch::_implicit; JP_TRACE_OUT; } virtual void getInfo(JPClass *cls, JPConversionInfo &info) override { } virtual jvalue convert(JPMatch &match) override { jvalue v; v.l = NULL; return v; } } _nullConversion; class JPConversionClass : public JPConversion { public: virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) override { JP_TRACE_IN("JPConversionClass::matches"); if (match.frame == NULL) return match.type = JPMatch::_none; JPClass* cls2 = PyJPClass_getJPClass(match.object); if (cls2 == NULL) return match.type = JPMatch::_none; match.conversion = this; match.closure = cls2; return match.type = JPMatch::_implicit; JP_TRACE_OUT; } virtual void getInfo(JPClass *cls, JPConversionInfo &info) override { JPJavaFrame frame = JPJavaFrame::outer(cls->getContext()); PyList_Append(info.implicit, (PyObject*) PyJPClass_Type); } virtual jvalue convert(JPMatch &match) override { jvalue res; JPClass* cls2 = (JPClass*) match.closure; res.l = match.frame->NewLocalRef(cls2->getJavaClass()); return res; } } _classConversion; class JPConversionObject : public JPConversion { public: virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) override { JP_TRACE_IN("JPConversionObject::matches"); JPValue *value = match.getJavaSlot(); if (value == NULL || match.frame == NULL) return match.type = JPMatch::_none; match.conversion = this; JPClass *oc = value->getClass(); if (oc == NULL) return match.type = JPMatch::_none; if (oc == cls) { // hey, this is me! :) return match.type = JPMatch::_exact; } bool assignable = match.frame->IsAssignableFrom(oc->getJavaClass(), cls->getJavaClass()) != 0; JP_TRACE("assignable", assignable, oc->getCanonicalName(), cls->getCanonicalName()); match.type = (assignable ? JPMatch::_implicit : JPMatch::_none); // This is the one except to the conversion rule patterns. // If it is a Java value then we must prevent it from proceeding // through the conversion rules even if it was not a match. // Thus the return result and the match type differ here. return JPMatch::_implicit; JP_TRACE_OUT; } virtual void getInfo(JPClass *cls, JPConversionInfo &info) override { JPJavaFrame frame = JPJavaFrame::outer(cls->getContext()); PyList_Append(info.exact, PyJPClass_create(frame, cls).get()); } virtual jvalue convert(JPMatch &match) override { jvalue res; JPValue* value = match.getJavaSlot(); res.l = match.frame->NewLocalRef(value->getValue().l); return res; } } _objectConversion; JPMatch::Type JPConversionJavaValue::matches(JPClass *cls, JPMatch &match) { JP_TRACE_IN("JPConversionJavaValue::matches"); JPValue *slot = match.getJavaSlot(); if (slot == NULL || slot->getClass() != cls) return match.type = JPMatch::_none; match.conversion = this; return match.type = JPMatch::_exact; JP_TRACE_OUT; } void JPConversionJavaValue::getInfo(JPClass *cls, JPConversionInfo &info) { JPJavaFrame frame = JPJavaFrame::outer(cls->getContext()); PyList_Append(info.exact, PyJPClass_create(frame, cls).get()); } jvalue JPConversionJavaValue::convert(JPMatch &match) { JPValue* value = match.getJavaSlot(); return *value; } JPConversionJavaValue _javaValueConversion; class JPConversionString : public JPConversion { public: virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) override { JP_TRACE_IN("JPConversionString::matches"); if (match.frame == NULL || !JPPyString::check(match.object)) return match.type = JPMatch::_none; match.conversion = this; if (cls == match.getContext()->_java_lang_String) return match.type = JPMatch::_exact; return match.type = JPMatch::_implicit; JP_TRACE_OUT; } virtual void getInfo(JPClass *cls, JPConversionInfo &info) override { PyList_Append(info.implicit, (PyObject*) & PyUnicode_Type); } virtual jvalue convert(JPMatch &match) override { jvalue res; string str = JPPyString::asStringUTF8(match.object); res.l = match.frame->fromStringUTF8(str); return res; } } _stringConversion; class JPConversionBox : public JPConversion { public: virtual jvalue convert(JPMatch &match) override { jvalue res; JPPyObjectVector args(match.object, NULL); JPClass *cls = (JPClass*) match.closure; JPValue pobj = cls->newInstance(*match.frame, args); res.l = pobj.getJavaObject(); return res; } } ; class JPConversionBoxBoolean : public JPConversionBox { public: JPMatch::Type matches(JPClass *cls, JPMatch &match) override { JP_TRACE_IN("JPConversionBoxBoolean::matches"); if (!PyBool_Check(match.object)) return match.type = JPMatch::_none; match.conversion = this; match.closure = match.frame->getContext()->_java_lang_Boolean; return match.type = JPMatch::_implicit; JP_TRACE_OUT; } virtual void getInfo(JPClass *cls, JPConversionInfo &info) override { PyList_Append(info.implicit, (PyObject*) & PyBool_Type); } } _boxBooleanConversion; class JPConversionBoxLong : public JPConversionBox { public: JPMatch::Type matches(JPClass *cls, JPMatch &match) override { JP_TRACE_IN("JPConversionBoxLong::matches"); if (match.frame == NULL) return match.type = JPMatch::_none; if (PyLong_CheckExact(match.object) || PyIndex_Check(match.object)) { match.conversion = this; return match.type = JPMatch::_implicit; } return match.type = JPMatch::_none; JP_TRACE_OUT; } virtual void getInfo(JPClass *cls, JPConversionInfo &info) override { PyObject *typing = PyImport_AddModule("jpype.protocol"); JPPyObject proto = JPPyObject::call(PyObject_GetAttrString(typing, "SupportsIndex")); PyList_Append(info.implicit, proto.get()); } jvalue convert(JPMatch &match) override { PyTypeObject* type = Py_TYPE(match.object); JPJavaFrame *frame = match.frame; const char *name = type->tp_name; match.closure = frame->getContext()->_java_lang_Long; if (strncmp(name, "numpy", 5) == 0) { // We only handle specific sized types, all others go to long. if (strcmp(&name[5], ".int8") == 0) match.closure = frame->getContext()->_java_lang_Byte; else if (strcmp(&name[5], ".int16") == 0) match.closure = frame->getContext()->_java_lang_Short; else if (strcmp(&name[5], ".int32") == 0) match.closure = frame->getContext()->_java_lang_Integer; } return JPConversionBox::convert(match); } } _boxLongConversion; class JPConversionBoxDouble : public JPConversionBox { public: virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) override { JP_TRACE_IN("JPConversionBoxDouble::matches"); if (match.frame == NULL) return match.type = JPMatch::_none; if (PyNumber_Check(match.object)) { match.conversion = this; return match.type = JPMatch::_implicit; } return match.type = JPMatch::_none; JP_TRACE_OUT; } virtual void getInfo(JPClass *cls, JPConversionInfo &info) override { PyObject *typing = PyImport_AddModule("jpype.protocol"); JPPyObject proto = JPPyObject::call(PyObject_GetAttrString(typing, "SupportsFloat")); PyList_Append(info.implicit, proto.get()); } virtual jvalue convert(JPMatch &match) override { JPJavaFrame *frame = match.frame; PyTypeObject* type = Py_TYPE(match.object); const char *name = type->tp_name; match.closure = frame->getContext()->_java_lang_Double; if (strncmp(name, "numpy", 5) == 0) { // We only handle specific sized types, all others go to double. if (strcmp(&name[5], ".float32") == 0) match.closure = frame->getContext()->_java_lang_Float; } return JPConversionBox::convert(match); } } _boxDoubleConversion; class JPConversionJavaObjectAny : public JPConversionBox { public: virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) override { JP_TRACE_IN("JPConversionJavaObjectAny::matches"); JPValue *value = match.getJavaSlot(); if (value == NULL || match.frame == NULL || value->getClass() == NULL) return match.type = JPMatch::_none; match.conversion = this; match.type = (value->getClass() == cls) ? JPMatch::_exact : JPMatch::_implicit; return match.type; JP_TRACE_OUT; } virtual void getInfo(JPClass *cls, JPConversionInfo &info) override { JPJavaFrame frame = JPJavaFrame::outer(cls->getContext()); PyList_Append(info.implicit, PyJPClass_create(frame, cls->getContext()->_java_lang_Object).get()); } virtual jvalue convert(JPMatch &match) override { jvalue res; JPJavaFrame *frame = match.frame; JPValue *value = match.getJavaSlot(); if (!value->getClass()->isPrimitive()) { res.l = frame->NewLocalRef(value->getJavaObject()); return res; } else { // Okay we need to box it. JPPrimitiveType* type = (JPPrimitiveType*) (value->getClass()); match.closure = type->getBoxedClass(frame->getContext()); res = JPConversionBox::convert(match); return res; } } } _javaObjectAnyConversion; class JPConversionJavaNumberAny : public JPConversionJavaObjectAny { public: virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) override { JP_TRACE_IN("JPConversionJavaNumberAny::matches"); JPContext *context = match.getContext(); JPValue *value = match.getJavaSlot(); // This converter only works for number types, thus boolean and char // are excluded. if (value == NULL || match.frame == NULL || value->getClass() == NULL || value->getClass() == context->_boolean || value->getClass() == context->_char) return match.type = JPMatch::_none; match.conversion = this; JPClass *oc = value->getClass(); // If it is the exact type, then it is exact if (oc == cls) return match.type = JPMatch::_exact; // If it is any primitive except char and boolean then implicit if (oc->isPrimitive()) return match.type = JPMatch::_implicit; // Otherwise check if it is assignable according to Java bool assignable = match.frame->IsAssignableFrom(oc->getJavaClass(), cls->getJavaClass()) != 0; return match.type = (assignable ? JPMatch::_implicit : JPMatch::_none); JP_TRACE_OUT; } virtual void getInfo(JPClass *cls, JPConversionInfo &info) override { PyList_Append(info.implicit, (PyObject*) PyJPNumberLong_Type); PyList_Append(info.implicit, (PyObject*) PyJPNumberFloat_Type); } } _javaNumberAnyConversion; class JPConversionUnbox : public JPConversion { public: virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) override { JPContext *context = match.getContext(); if (context == NULL) return match.type = JPMatch::_none; JPValue *slot = match.slot; JPPrimitiveType *pcls = (JPPrimitiveType*) cls; if (slot->getClass() != pcls->getBoxedClass(context)) return match.type = JPMatch::_none; match.conversion = this; match.closure = cls; return match.type = JPMatch::_implicit; } virtual void getInfo(JPClass *cls, JPConversionInfo &info) override { JPJavaFrame frame = JPJavaFrame::outer(cls->getContext()); JPPrimitiveType *pcls = (JPPrimitiveType*) cls; JPContext *context = cls->getContext(); PyList_Append(info.implicit, PyJPClass_create(frame, pcls->getBoxedClass(context)).get()); } virtual jvalue convert(JPMatch &match) override { JPValue* value = match.getJavaSlot(); JPClass *cls = (JPClass*) match.closure; return cls->getValueFromObject(*value); } } _unboxConversion; class JPConversionProxy : public JPConversion { public: virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) override { JP_TRACE_IN("JPConversionProxy::matches"); JPProxy* proxy = PyJPProxy_getJPProxy(match.object); if (proxy == NULL || match.frame == NULL) return match.type = JPMatch::_none; // Check if any of the interfaces matches ... vector itf = proxy->getInterfaces(); for (unsigned int i = 0; i < itf.size(); i++) { if (match.frame->IsAssignableFrom(itf[i]->getJavaClass(), cls->getJavaClass())) { JP_TRACE("implicit proxy"); match.conversion = this; return match.type = JPMatch::_implicit; } } return match.type = JPMatch::_none; JP_TRACE_OUT; } virtual void getInfo(JPClass *cls, JPConversionInfo &info) override { } virtual jvalue convert(JPMatch &match) override { return PyJPProxy_getJPProxy(match.object)->getProxy(); } } _proxyConversion; JPConversion *hintsConversion = &_hintsConversion; JPConversion *charArrayConversion = &_charArrayConversion; JPConversion *byteArrayConversion = &_byteArrayConversion; JPConversion *bufferConversion = &_bufferConversion; JPConversion *sequenceConversion = &_sequenceConversion; JPConversion *nullConversion = &_nullConversion; JPConversion *classConversion = &_classConversion; JPConversion *objectConversion = &_objectConversion; JPConversion *javaObjectAnyConversion = &_javaObjectAnyConversion; JPConversion *javaNumberAnyConversion = &_javaNumberAnyConversion; JPConversion *javaValueConversion = &_javaValueConversion; JPConversion *stringConversion = &_stringConversion; JPConversion *boxBooleanConversion = &_boxBooleanConversion; JPConversion *boxLongConversion = &_boxLongConversion; JPConversion *boxDoubleConversion = &_boxDoubleConversion; JPConversion *unboxConversion = &_unboxConversion; JPConversion *proxyConversion = &_proxyConversion; jpype-1.3.0/native/common/jp_classloader.cpp000066400000000000000000000115531405671516700211320ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include #include #include #include jobject JPClassLoader::getBootLoader() { return m_BootLoader.get(); } static jobject toURL(JPJavaFrame &frame, const string& path) { // file = new File("org.jpype.jar"); jclass fileClass = frame.FindClass("java/io/File"); jmethodID newFile = frame.GetMethodID(fileClass, "", "(Ljava/lang/String;)V"); jvalue v[3]; v[0].l = frame.NewStringUTF(path.c_str()); jobject file = frame.NewObjectA(fileClass, newFile, v); // url = file.toURI().toURL(); jmethodID toURI = frame.GetMethodID(fileClass, "toURI", "()Ljava/net/URI;"); jobject uri = frame.CallObjectMethodA(file, toURI, NULL); jclass uriClass = frame.GetObjectClass(uri); jmethodID toURL = frame.GetMethodID(uriClass, "toURL", "()Ljava/net/URL;"); return frame.CallObjectMethodA(uri, toURL, NULL); } JPClassLoader::JPClassLoader(JPJavaFrame& frame) { JP_TRACE_IN("JPClassLoader::JPClassLoader"); m_Context = frame.getContext(); // Define the class loader m_ClassClass = JPClassRef(frame, frame.FindClass("java/lang/Class")); m_ForNameID = frame.GetStaticMethodID(m_ClassClass.get(), "forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"); jclass classLoaderClass = frame.FindClass("java/lang/ClassLoader"); jmethodID getSystemClassLoader = frame.GetStaticMethodID(classLoaderClass, "getSystemClassLoader", "()Ljava/lang/ClassLoader;"); m_SystemClassLoader = JPObjectRef(frame, frame.CallStaticObjectMethodA(classLoaderClass, getSystemClassLoader, 0)); jclass dynamicLoaderClass = frame.getEnv()->FindClass("org/jpype/classloader/DynamicClassLoader"); if (dynamicLoaderClass != NULL) { // Easy the Dynamic loader is already in the path, so just use it as the bootloader jmethodID newDyLoader = frame.GetMethodID(dynamicLoaderClass, "", "(Ljava/lang/ClassLoader;)V"); jvalue v; v.l = m_SystemClassLoader.get(); m_BootLoader = JPObjectRef(frame, frame.NewObjectA(dynamicLoaderClass, newDyLoader, &v)); return; } frame.ExceptionClear(); // Harder, we need to find the _jpype module and use __file__ to obtain a // path. JPPyObject pypath = JPPyObject::call(PyObject_GetAttrString(PyJPModule, "__file__")); string path = JPPyString::asStringUTF8(pypath.get()); string::size_type i = path.find_last_of('\\'); if (i == string::npos) i = path.find_last_of('/'); if (i == string::npos) JP_RAISE(PyExc_RuntimeError, "Can't find jar path"); path = path.substr(0, i + 1); jobject url1 = toURL(frame, path + "org.jpype.jar"); // jobject url2 = toURL(frame, path + "lib/asm-8.0.1.jar"); // urlArray = new URL[]{url}; jclass urlClass = frame.GetObjectClass(url1); jobjectArray urlArray = frame.NewObjectArray(1, urlClass, NULL); frame.SetObjectArrayElement(urlArray, 0, url1); // frame.SetObjectArrayElement(urlArray, 1, url2); // cl = new URLClassLoader(urlArray); jclass urlLoaderClass = frame.FindClass("java/net/URLClassLoader"); jmethodID newURLClassLoader = frame.GetMethodID(urlLoaderClass, "", "([Ljava/net/URL;Ljava/lang/ClassLoader;)V"); jvalue v[3]; v[0].l = (jobject) urlArray; v[1].l = (jobject) m_SystemClassLoader.get(); jobject cl = frame.NewObjectA(urlLoaderClass, newURLClassLoader, v); // Class dycl = Class.forName("org.jpype.classloader.DynamicClassLoader", true, cl); v[0].l = frame.NewStringUTF("org.jpype.classloader.DynamicClassLoader"); v[1].z = true; v[2].l = cl; jclass dyClass = (jclass) frame.CallStaticObjectMethodA(m_ClassClass.get(), m_ForNameID, v); // dycl.newInstance(systemClassLoader); jmethodID newDyLoader = frame.GetMethodID(dyClass, "", "(Ljava/lang/ClassLoader;)V"); v[0].l = cl; m_BootLoader = JPObjectRef(frame, frame.NewObjectA(dyClass, newDyLoader, v)); JP_TRACE_OUT; // GCOVR_EXCL_LINE } jclass JPClassLoader::findClass(JPJavaFrame& frame, const string& name) { #ifdef ANDROID string cname = name; for (int i = 0; i < cname.size(); ++i) if (cname[i] == '.') cname[i] = '/'; return frame.FindClass(cname); #else jvalue v[3]; v[0].l = frame.NewStringUTF(name.c_str()); v[1].z = true; v[2].l = m_BootLoader.get(); return (jclass) frame.CallStaticObjectMethodA(m_ClassClass.get(), m_ForNameID, v); #endif } jpype-1.3.0/native/common/jp_classtype.cpp000066400000000000000000000034051405671516700206420ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include #include #include // Class has special rules JPClassType::JPClassType(JPJavaFrame& frame, jclass clss, const string& name, JPClass* super, JPClassList& interfaces, jint modifiers) : JPClass(frame, clss, name, super, interfaces, modifiers) { } JPClassType::~JPClassType() { } JPMatch::Type JPClassType::findJavaConversion(JPMatch& match) { JP_TRACE_IN("JPClass::findJavaConversion"); if (nullConversion->matches(this, match) != JPMatch::_none) return match.type; if (objectConversion->matches(this, match) != JPMatch::_none) return match.type; if (classConversion->matches(this, match) != JPMatch::_none) return match.type; return match.type = JPMatch::_none; JP_TRACE_OUT; } void JPClassType::getConversionInfo(JPConversionInfo &info) { JPJavaFrame frame = JPJavaFrame::outer(m_Context); nullConversion->getInfo(this, info); objectConversion->getInfo(this, info); classConversion->getInfo(this, info); PyList_Append(info.ret, PyJPClass_create(frame, this).get()); }jpype-1.3.0/native/common/jp_context.cpp000066400000000000000000000410131405671516700203140ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "pyjp.h" #include "jp_typemanager.h" #include "jp_boxedtype.h" #include "jp_stringtype.h" #include "jp_classloader.h" #include "jp_voidtype.h" #include "jp_booleantype.h" #include "jp_bytetype.h" #include "jp_chartype.h" #include "jp_shorttype.h" #include "jp_inttype.h" #include "jp_longtype.h" #include "jp_floattype.h" #include "jp_doubletype.h" #include "jp_proxy.h" #include "jp_platform.h" #include "jp_gc.h" JPResource::~JPResource() { } #define USE_JNI_VERSION JNI_VERSION_1_4 void JPRef_failed() { JP_RAISE(PyExc_SystemError, "NULL context in JPRef()"); } JPContext::JPContext() { m_JavaVM = 0; _void = 0; _byte = 0; _boolean = 0; _char = 0; _short = 0; _int = 0; _long = 0; _float = 0; _double = 0; _java_lang_Void = 0; _java_lang_Boolean = 0; _java_lang_Byte = 0; _java_lang_Character = 0; _java_lang_Short = 0; _java_lang_Integer = 0; _java_lang_Long = 0; _java_lang_Float = 0; _java_lang_Double = 0; _java_lang_Object = 0; _java_lang_Class = 0; _java_lang_String = 0; _java_lang_reflect_Method = 0; _java_lang_reflect_Field = 0; _java_nio_ByteBuffer = 0; m_TypeManager = 0; m_ClassLoader = 0; m_Object_ToStringID = 0; m_Object_EqualsID = 0; m_Running = false; // Java Functions m_Object_ToStringID = NULL; m_Object_EqualsID = NULL; m_Object_HashCodeID = NULL; m_CallMethodID = NULL; m_Class_GetNameID = NULL; m_Context_collectRectangularID = NULL; m_Context_assembleID = NULL; m_String_ToCharArrayID = NULL; m_Context_CreateExceptionID = NULL; m_Context_GetExcClassID = NULL; m_Context_GetExcValueID = NULL; m_CompareToID = NULL; m_Buffer_IsReadOnlyID = NULL; m_Context_OrderID = NULL; m_Object_GetClassID = NULL; m_Throwable_GetCauseID = NULL; m_Context_GetStackFrameID = NULL; m_Embedded = false; m_GC = new JPGarbageCollection(this); } JPContext::~JPContext() { delete m_TypeManager; delete m_GC; } bool JPContext::isRunning() { if (m_JavaVM == NULL || !m_Running) { return false; } return true; } /** throw a JPypeException if the JVM is not started */ void assertJVMRunning(JPContext* context, const JPStackInfo& info) { if (_JVMNotRunning == NULL) { _JVMNotRunning = PyObject_GetAttrString(PyJPModule, "JVMNotRunning"); JP_PY_CHECK(); Py_INCREF(_JVMNotRunning); } if (context == NULL) { throw JPypeException(JPError::_python_exc, _JVMNotRunning, "Java Context is null", info); } if (!context->isRunning()) { throw JPypeException(JPError::_python_exc, _JVMNotRunning, "Java Virtual Machine is not running", info); } } void JPContext::loadEntryPoints(const string& path) { JP_TRACE_IN("JPContext::loadEntryPoints"); JPPlatformAdapter *platform = JPPlatformAdapter::getAdapter(); // Load symbols from the shared library platform->loadLibrary((char*) path.c_str()); CreateJVM_Method = (jint(JNICALL *)(JavaVM **, void **, void *) )platform->getSymbol("JNI_CreateJavaVM"); GetCreatedJVMs_Method = (jint(JNICALL *)(JavaVM **, jsize, jsize*))platform->getSymbol("JNI_GetCreatedJavaVMs"); JP_TRACE_OUT; } void JPContext::startJVM(const string& vmPath, const StringVector& args, bool ignoreUnrecognized, bool convertStrings, bool interrupt) { JP_TRACE_IN("JPContext::startJVM"); JP_TRACE("Convert strings", convertStrings); m_ConvertStrings = convertStrings; // Get the entry points in the shared library try { JP_TRACE("Load entry points"); loadEntryPoints(vmPath); } catch (JPypeException& ex) { ex.getMessage(); throw; } // Pack the arguments JP_TRACE("Pack arguments"); JavaVMInitArgs jniArgs; jniArgs.options = NULL; // prepare this ... jniArgs.version = USE_JNI_VERSION; jniArgs.ignoreUnrecognized = ignoreUnrecognized; JP_TRACE("IgnoreUnrecognized", ignoreUnrecognized); jniArgs.nOptions = (jint) args.size(); JP_TRACE("NumOptions", jniArgs.nOptions); jniArgs.options = new JavaVMOption[jniArgs.nOptions]; memset(jniArgs.options, 0, sizeof (JavaVMOption) * jniArgs.nOptions); for (int i = 0; i < jniArgs.nOptions; i++) { JP_TRACE("Option", args[i]); jniArgs.options[i].optionString = (char*) args[i].c_str(); } // Launch the JVM JNIEnv* env = NULL; JP_TRACE("Create JVM"); try { CreateJVM_Method(&m_JavaVM, (void**) &env, (void*) &jniArgs); } catch (...) { JP_TRACE("Exception in CreateJVM?"); } JP_TRACE("JVM created"); delete [] jniArgs.options; if (m_JavaVM == NULL) { JP_TRACE("Unable to start"); JP_RAISE(PyExc_RuntimeError, "Unable to start JVM"); } initializeResources(env, interrupt); JP_TRACE_OUT; } void JPContext::attachJVM(JNIEnv* env) { env->GetJavaVM(&m_JavaVM); #ifndef ANDROID m_Embedded = true; #endif initializeResources(env, false); } void JPContext::initializeResources(JNIEnv* env, bool interrupt) { JPJavaFrame frame = JPJavaFrame::external(this, env); // This is the only frame that we can use until the system // is initialized. Any other frame creation will result in an error. jclass throwableClass = (jclass) frame.FindClass("java/lang/Throwable"); m_Throwable_GetCauseID = frame.GetMethodID(throwableClass, "getCause", "()Ljava/lang/Throwable;"); m_Throwable_GetMessageID = frame.GetMethodID(throwableClass, "getMessage", "()Ljava/lang/String;"); // After the JVM is created but before the context is started, we need // to set up all the services that the context will need. JP_TRACE("Initialize"); // We need these first because if anything goes south this is the first // thing that will get hit. jclass objectClass = frame.FindClass("java/lang/Object"); m_Object_ToStringID = frame.GetMethodID(objectClass, "toString", "()Ljava/lang/String;"); m_Object_EqualsID = frame.GetMethodID(objectClass, "equals", "(Ljava/lang/Object;)Z"); m_Object_HashCodeID = frame.GetMethodID(objectClass, "hashCode", "()I"); m_Object_GetClassID = frame.GetMethodID(objectClass, "getClass", "()Ljava/lang/Class;"); m_NoSuchMethodError = JPClassRef(frame, (jclass) frame.FindClass("java/lang/NoSuchMethodError")); m_RuntimeException = JPClassRef(frame, (jclass) frame.FindClass("java/lang/RuntimeException")); jclass stringClass = frame.FindClass("java/lang/String"); m_String_ToCharArrayID = frame.GetMethodID(stringClass, "toCharArray", "()[C"); jclass classClass = frame.FindClass("java/lang/Class"); m_Class_GetNameID = frame.GetMethodID(classClass, "getName", "()Ljava/lang/String;"); // Bootloader needs to go first so we can load classes m_ClassLoader = new JPClassLoader(frame); JP_TRACE("Install native"); // Start the rest of the services m_TypeManager = new JPTypeManager(frame); // Prepare to launch JP_TRACE("Start Context"); m_ContextClass = JPClassRef(frame, (jclass) m_ClassLoader->findClass(frame, "org.jpype.JPypeContext")); jclass contextClass = m_ContextClass.get(); m_Context_GetStackFrameID = frame.GetMethodID(contextClass, "getStackTrace", "(Ljava/lang/Throwable;Ljava/lang/Throwable;)[Ljava/lang/Object;"); jmethodID startMethod = frame.GetStaticMethodID(contextClass, "createContext", "(JLjava/lang/ClassLoader;Ljava/lang/String;Z)Lorg/jpype/JPypeContext;"); // Launch jvalue val[4]; val[0].j = (jlong) this; val[1].l = m_ClassLoader->getBootLoader(); val[2].l = 0; val[3].z = interrupt; if (!m_Embedded) { JPPyObject import = JPPyObject::call(PyImport_AddModule("importlib.util")); JPPyObject jpype = JPPyObject::call(PyObject_CallMethod(import.get(), "find_spec", "s", "_jpype")); JPPyObject origin = JPPyObject::call(PyObject_GetAttrString(jpype.get(), "origin")); val[2].l = frame.fromStringUTF8(JPPyString::asStringUTF8(origin.get())); import.incref(); // The documentation specifies that PyImport_AddModule must return a // new reference, but that is not happening in Python 3.10 // so we are triggering a gc assertion failure. To prevent // the failure manually up the reference counter here. } m_JavaContext = JPObjectRef(frame, frame.CallStaticObjectMethodA(contextClass, startMethod, val)); // Post launch JP_TRACE("Connect resources"); // Hook up the type manager jmethodID getTypeManager = frame.GetMethodID(contextClass, "getTypeManager", "()Lorg/jpype/manager/TypeManager;"); m_TypeManager->m_JavaTypeManager = JPObjectRef(frame, frame.CallObjectMethodA(m_JavaContext.get(), getTypeManager, 0)); // Set up methods after everything is start so we get better error // messages m_CallMethodID = frame.GetMethodID(contextClass, "callMethod", "(Ljava/lang/reflect/Method;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"); m_Context_collectRectangularID = frame.GetMethodID(contextClass, "collectRectangular", "(Ljava/lang/Object;)[Ljava/lang/Object;"); m_Context_assembleID = frame.GetMethodID(contextClass, "assemble", "([ILjava/lang/Object;)Ljava/lang/Object;"); m_Context_GetFunctionalID = frame.GetMethodID(contextClass, "getFunctional", "(Ljava/lang/Class;)Ljava/lang/String;"); m_Context_CreateExceptionID = frame.GetMethodID(contextClass, "createException", "(JJ)Ljava/lang/Exception;"); m_Context_GetExcClassID = frame.GetMethodID(contextClass, "getExcClass", "(Ljava/lang/Throwable;)J"); m_Context_GetExcValueID = frame.GetMethodID(contextClass, "getExcValue", "(Ljava/lang/Throwable;)J"); m_Context_OrderID = frame.GetMethodID(contextClass, "order", "(Ljava/nio/Buffer;)Z"); m_Context_IsPackageID = frame.GetMethodID(contextClass, "isPackage", "(Ljava/lang/String;)Z"); m_Context_GetPackageID = frame.GetMethodID(contextClass, "getPackage", "(Ljava/lang/String;)Lorg/jpype/pkg/JPypePackage;"); m_Context_ClearInterruptID = frame.GetStaticMethodID(contextClass, "clearInterrupt", "(Z)V"); jclass packageClass = m_ClassLoader->findClass(frame, "org.jpype.pkg.JPypePackage"); m_Package_GetObjectID = frame.GetMethodID(packageClass, "getObject", "(Ljava/lang/String;)Ljava/lang/Object;"); m_Package_GetContentsID = frame.GetMethodID(packageClass, "getContents", "()[Ljava/lang/String;"); m_Context_NewWrapperID = frame.GetMethodID(contextClass, "newWrapper", "(J)V"); m_Array = JPClassRef(frame, frame.FindClass("java/lang/reflect/Array")); m_Array_NewInstanceID = frame.GetStaticMethodID(m_Array.get(), "newInstance", "(Ljava/lang/Class;[I)Ljava/lang/Object;"); jclass bufferClass = frame.FindClass("java/nio/Buffer"); m_Buffer_IsReadOnlyID = frame.GetMethodID(bufferClass, "isReadOnly", "()Z"); jclass comparableClass = frame.FindClass("java/lang/Comparable"); m_CompareToID = frame.GetMethodID(comparableClass, "compareTo", "(Ljava/lang/Object;)I"); jclass proxyClass = getClassLoader()->findClass(frame, "org.jpype.proxy.JPypeProxy"); m_ProxyClass = JPClassRef(frame, proxyClass); m_Proxy_NewID = frame.GetStaticMethodID(m_ProxyClass.get(), "newProxy", "(Lorg/jpype/JPypeContext;JJ[Ljava/lang/Class;)Lorg/jpype/proxy/JPypeProxy;"); m_Proxy_NewInstanceID = frame.GetMethodID(m_ProxyClass.get(), "newInstance", "()Ljava/lang/Object;"); m_GC->init(frame); _java_nio_ByteBuffer = this->getTypeManager()->findClassByName("java.nio.ByteBuffer"); // Testing code to make sure C++ exceptions are handled. // FIXME find a way to call this from instrumentation. // throw std::runtime_error("Failed"); // Everything is started. m_Running = true; } void JPContext::onShutdown() { m_Running = false; } void JPContext::shutdownJVM(bool destroyJVM, bool freeJVM) { JP_TRACE_IN("JPContext::shutdown"); if (m_JavaVM == NULL) JP_RAISE(PyExc_RuntimeError, "Attempt to shutdown without a live JVM"); // if (m_Embedded) // JP_RAISE(PyExc_RuntimeError, "Cannot shutdown from embedded Python"); // Wait for all non-demon threads to terminate if (destroyJVM) { JP_TRACE("Destroy JVM"); JPPyCallRelease call; m_JavaVM->DestroyJavaVM(); } // unload the jvm library if (freeJVM) { JP_TRACE("Unload JVM"); m_JavaVM = NULL; JPPlatformAdapter::getAdapter()->unloadLibrary(); } JP_TRACE("Delete resources"); for (std::list::iterator iter = m_Resources.begin(); iter != m_Resources.end(); ++iter) { delete *iter; } m_Resources.clear(); JP_TRACE_OUT; } void JPContext::ReleaseGlobalRef(jobject obj) { JP_TRACE_IN("JPContext::ReleaseGlobalRef", obj); // Check if the JVM is already shutdown if (m_JavaVM == NULL) return; // Get the environment and release the resource if we can. // Do not attach the thread if called from an unattached thread it is // likely a shutdown anyway. JNIEnv* env; jint res = m_JavaVM->functions->GetEnv(m_JavaVM, (void**) &env, USE_JNI_VERSION); if (res != JNI_EDETACHED) env->functions->DeleteGlobalRef(env, obj); JP_TRACE_OUT; } /*****************************************************************************/ // Thread code void JPContext::attachCurrentThread() { JNIEnv* env; jint res = m_JavaVM->functions->AttachCurrentThread(m_JavaVM, (void**) &env, NULL); if (res != JNI_OK) JP_RAISE(PyExc_RuntimeError, "Unable to attach to thread"); } void JPContext::attachCurrentThreadAsDaemon() { JNIEnv* env; jint res = m_JavaVM->functions->AttachCurrentThreadAsDaemon(m_JavaVM, (void**) &env, NULL); if (res != JNI_OK) JP_RAISE(PyExc_RuntimeError, "Unable to attach to thread as daemon"); } bool JPContext::isThreadAttached() { JNIEnv* env; return JNI_OK == m_JavaVM->functions->GetEnv(m_JavaVM, (void**) &env, USE_JNI_VERSION); } void JPContext::detachCurrentThread() { m_JavaVM->functions->DetachCurrentThread(m_JavaVM); } JNIEnv* JPContext::getEnv() { JNIEnv* env = NULL; if (m_JavaVM == NULL) { JP_RAISE(PyExc_RuntimeError, "JVM is null"); } // Get the environment jint res = m_JavaVM->functions->GetEnv(m_JavaVM, (void**) &env, USE_JNI_VERSION); // If we don't have an environment then we are in a thread, so we must attach if (res == JNI_EDETACHED) { // We will attach as daemon so that the newly attached thread does // not deadlock the shutdown. The user can convert later if they want. res = m_JavaVM->AttachCurrentThreadAsDaemon((void**) &env, NULL); if (res != JNI_OK) JP_RAISE(PyExc_RuntimeError, "Unable to attach to local thread"); } return env; } extern "C" JNIEXPORT void JNICALL Java_org_jpype_JPypeContext_onShutdown (JNIEnv *env, jobject obj, jlong contextPtr) { ((JPContext*) contextPtr)->onShutdown(); } /********************************************************************** * Interrupts are complex. Both Java and Python want to handle the * interrupt, but only one can be in control. Java starts later and * installs its handler over Python as a chain. If Java handles it then * the JVM will terminate which leaves Python with a bunch of bad * references which tends to lead to segfaults. So we need to disable * the Java one by routing it back to Python. But if we do so then * Java wont respect Ctrl+C. So we need to handle the interrupt, convert * it to a wait interrupt so that Java can break at the next I/O and * then trip Python signal handler so the Python gets the interrupt. * * But this leads to a few race conditions. * * If the control is in Java then it will get the interrupt next time * it hits Python code when the returned object is checked resulting * InterruptedException. Now we have two exceptions on the stack, * the one from Java and the one from Python. We check to see if * Python has a pending interrupt and eat the Java one. * * If the control is in Java and it hits an I/O call. This generates * InterruptedException which again transfers control to Python where * the Exception is resolved. * * If the control is in Python when the interrupt occurs, then * we have a bogus Java interrupt sitting on the main thread that the next * Java call will trip over. So we need to call clearInterrupt(false). * This checks clears the interrupt in C++ and in Java. * */ static int interruptState = 0; extern "C" JNIEXPORT void JNICALL Java_org_jpype_JPypeSignal_interruptPy (JNIEnv *env, jclass cls) { interruptState = 1; PyErr_SetInterrupt(); } extern "C" JNIEXPORT void JNICALL Java_org_jpype_JPypeSignal_acknowledgePy (JNIEnv *env, jclass cls) { interruptState = 0; } int hasInterrupt() { return interruptState != 0; } jpype-1.3.0/native/common/jp_convert.cpp000066400000000000000000000137371405671516700203240ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" namespace { template class Convert { public: static jvalue toZ(void* c) { jvalue v; v.z = (*(T*) c) != 0; return v; } static jvalue toB(void* c) { jvalue v; v.b = (jbyte) (*(T*) c); return v; } static jvalue toC(void* c) { jvalue v; v.c = (jchar) (*(T*) c); return v; } static jvalue toS(void* c) { jvalue v; v.s = (jshort) (*(T*) c); return v; } static jvalue toI(void* c) { jvalue v; v.i = (jint) (*(T*) c); return v; } static jvalue toJ(void* c) { jvalue v; v.j = (jlong) (*(T*) c); return v; } static jvalue toF(void* c) { jvalue v; v.f = (jfloat) (*(T*) c); return v; } static jvalue toD(void* c) { jvalue v; v.d = (jdouble) (*(T*) c); return v; } } ; } // namespace jconverter getConverter(const char* from, int itemsize, const char* to) { // If not specified then the type is bytes if (from == NULL) from = "B"; // Standard size for 'l' is 4 in docs, but numpy uses format 'l' for long long if (itemsize == 8 && from[0] == 'l') from = "q"; if (itemsize == 8 && from[0] == 'L') from = "Q"; switch (from[0]) { case '?': case 'c': case 'b': switch (to[0]) { case 'z': return &Convert::toZ; case 'b': return &Convert::toB; case 'c': return &Convert::toC; case 's': return &Convert::toS; case 'i': return &Convert::toI; case 'j': return &Convert::toJ; case 'f': return &Convert::toF; case 'd': return &Convert::toD; } return 0; case 'B': switch (to[0]) { case 'z': return &Convert::toZ; case 'b': return &Convert::toB; case 'c': return &Convert::toC; case 's': return &Convert::toS; case 'i': return &Convert::toI; case 'j': return &Convert::toJ; case 'f': return &Convert::toF; case 'd': return &Convert::toD; } return 0; case 'h': switch (to[0]) { case 'z': return &Convert::toZ; case 'b': return &Convert::toB; case 'c': return &Convert::toC; case 's': return &Convert::toS; case 'i': return &Convert::toI; case 'j': return &Convert::toJ; case 'f': return &Convert::toF; case 'd': return &Convert::toD; } return 0; case 'H': switch (to[0]) { case 'z': return &Convert::toZ; case 'b': return &Convert::toB; case 'c': return &Convert::toC; case 's': return &Convert::toS; case 'i': return &Convert::toI; case 'j': return &Convert::toJ; case 'f': return &Convert::toF; case 'd': return &Convert::toD; } return 0; case 'i': case 'l': switch (to[0]) { case 'z': return &Convert::toZ; case 'b': return &Convert::toB; case 'c': return &Convert::toC; case 's': return &Convert::toS; case 'i': return &Convert::toI; case 'j': return &Convert::toJ; case 'f': return &Convert::toF; case 'd': return &Convert::toD; } return 0; case 'I': case 'L': switch (to[0]) { case 'z': return &Convert::toZ; case 'b': return &Convert::toB; case 'c': return &Convert::toC; case 's': return &Convert::toS; case 'i': return &Convert::toI; case 'j': return &Convert::toJ; case 'f': return &Convert::toF; case 'd': return &Convert::toD; } return 0; case 'q': switch (to[0]) { case 'z': return &Convert::toZ; case 'b': return &Convert::toB; case 'c': return &Convert::toC; case 's': return &Convert::toS; case 'i': return &Convert::toI; case 'j': return &Convert::toJ; case 'f': return &Convert::toF; case 'd': return &Convert::toD; } return 0; case 'Q': switch (to[0]) { case 'z': return &Convert::toZ; case 'b': return &Convert::toB; case 'c': return &Convert::toC; case 's': return &Convert::toS; case 'i': return &Convert::toI; case 'j': return &Convert::toJ; case 'f': return &Convert::toF; case 'd': return &Convert::toD; } return 0; case 'f': switch (to[0]) { case 'z': return &Convert::toZ; case 'b': return &Convert::toB; case 'c': return &Convert::toC; case 's': return &Convert::toS; case 'i': return &Convert::toI; case 'j': return &Convert::toJ; case 'f': return &Convert::toF; case 'd': return &Convert::toD; } return 0; case 'd': switch (to[0]) { case 'z': return &Convert::toZ; case 'b': return &Convert::toB; case 'c': return &Convert::toC; case 's': return &Convert::toS; case 'i': return &Convert::toI; case 'j': return &Convert::toJ; case 'f': return &Convert::toF; case 'd': return &Convert::toD; } return 0; case 'n': case 'N': case 'P': default: return 0; } } jpype-1.3.0/native/common/jp_doubletype.cpp000066400000000000000000000233241405671516700210110ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "pyjp.h" #include "jp_array.h" #include "jp_primitive_accessor.h" #include "jp_doubletype.h" JPDoubleType::JPDoubleType() : JPPrimitiveType("double") { } JPDoubleType::~JPDoubleType() { } JPPyObject JPDoubleType::convertToPythonObject(JPJavaFrame& frame, jvalue value, bool cast) { PyTypeObject * wrapper = getHost(); JPPyObject obj = JPPyObject::call(wrapper->tp_alloc(wrapper, 0)); ((PyFloatObject*) obj.get())->ob_fval = value.d; PyJPValue_assignJavaSlot(frame, obj.get(), JPValue(this, value)); return obj; } JPValue JPDoubleType::getValueFromObject(const JPValue& obj) { JPContext *context = obj.getClass()->getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); jvalue v; jobject jo = obj.getValue().l; JPBoxedType* jb = (JPBoxedType*) frame.findClassForObject(jo); field(v) = (type_t) frame.CallDoubleMethodA(jo, jb->m_DoubleValueID, 0); return JPValue(this, v); } static JPConversionAsFloat asDoubleConversion; static JPConversionLongAsFloat asDoubleLongConversion; static JPConversionFloatWiden doubleWidenConversion; class JPConversionAsDoubleExact : public JPConversionAsFloat { public: virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) override { if (!PyFloat_CheckExact(match.object)) return match.type = JPMatch::_none; match.conversion = this; return match.type = JPMatch::_exact; } } asDoubleExactConversion; class JPConversionAsJDouble : public JPConversionJavaValue { public: virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) override { JPValue *value = match.getJavaSlot(); if (value == NULL) return match.type = JPMatch::_none; match.type = JPMatch::_none; // Implied conversion from boxed to primitive (JLS 5.1.8) if (javaValueConversion->matches(cls, match) || unboxConversion->matches(cls, match)) return match.type; // Consider widening JPClass *cls2 = value->getClass(); if (cls2->isPrimitive()) { // https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.2 JPPrimitiveType *prim = (JPPrimitiveType*) cls2; switch (prim->getTypeCode()) { case 'B': case 'S': case 'C': case 'I': case 'J': case 'F': match.conversion = &doubleWidenConversion; return match.type = JPMatch::_implicit; default: break; } } // Unboxing must be to the from the exact boxed type (JLS 5.1.8) return JPMatch::_implicit; } virtual void getInfo(JPClass *cls, JPConversionInfo &info) override { JPContext *context = cls->getContext(); PyList_Append(info.exact, (PyObject*) context->_double->getHost()); PyList_Append(info.implicit, (PyObject*) context->_byte->getHost()); PyList_Append(info.implicit, (PyObject*) context->_char->getHost()); PyList_Append(info.implicit, (PyObject*) context->_short->getHost()); PyList_Append(info.implicit, (PyObject*) context->_int->getHost()); PyList_Append(info.implicit, (PyObject*) context->_long->getHost()); PyList_Append(info.implicit, (PyObject*) context->_float->getHost()); unboxConversion->getInfo(cls, info); } } asJDoubleConversion; JPMatch::Type JPDoubleType::findJavaConversion(JPMatch &match) { JP_TRACE_IN("JPDoubleType::findJavaConversion"); if (match.object == Py_None) return match.type = JPMatch::_none; if (asJDoubleConversion.matches(this, match) || asDoubleExactConversion.matches(this, match) || asDoubleLongConversion.matches(this, match) || asDoubleConversion.matches(this, match)) return match.type; return match.type = JPMatch::_none; JP_TRACE_OUT; } void JPDoubleType::getConversionInfo(JPConversionInfo &info) { JPJavaFrame frame = JPJavaFrame::outer(m_Context); asJDoubleConversion.getInfo(this, info); asDoubleExactConversion.getInfo(this, info); asDoubleLongConversion.getInfo(this, info); asDoubleConversion.getInfo(this, info); PyList_Append(info.ret, PyJPClass_create(frame, this).get()); } jarray JPDoubleType::newArrayOf(JPJavaFrame& frame, jsize sz) { return frame.NewDoubleArray(sz); } JPPyObject JPDoubleType::getStaticField(JPJavaFrame& frame, jclass c, jfieldID fid) { jvalue v; field(v) = frame.GetStaticDoubleField(c, fid); return convertToPythonObject(frame, v, false); } JPPyObject JPDoubleType::getField(JPJavaFrame& frame, jobject c, jfieldID fid) { jvalue v; field(v) = frame.GetDoubleField(c, fid); return convertToPythonObject(frame, v, false); } JPPyObject JPDoubleType::invokeStatic(JPJavaFrame& frame, jclass claz, jmethodID mth, jvalue* val) { jvalue v; { JPPyCallRelease call; field(v) = frame.CallStaticDoubleMethodA(claz, mth, val); } return convertToPythonObject(frame, v, false); } JPPyObject JPDoubleType::invoke(JPJavaFrame& frame, jobject obj, jclass clazz, jmethodID mth, jvalue* val) { jvalue v; { JPPyCallRelease call; if (clazz == NULL) field(v) = frame.CallDoubleMethodA(obj, mth, val); else field(v) = frame.CallNonvirtualDoubleMethodA(obj, clazz, mth, val); } return convertToPythonObject(frame, v, false); } void JPDoubleType::setStaticField(JPJavaFrame& frame, jclass c, jfieldID fid, PyObject* obj) { JPMatch match(&frame, obj); if (findJavaConversion(match) < JPMatch::_implicit) JP_RAISE(PyExc_TypeError, "Unable to convert to Java double"); type_t val = field(match.convert()); frame.SetStaticDoubleField(c, fid, val); } void JPDoubleType::setField(JPJavaFrame& frame, jobject c, jfieldID fid, PyObject* obj) { JPMatch match(&frame, obj); if (findJavaConversion(match) < JPMatch::_implicit) JP_RAISE(PyExc_TypeError, "Unable to convert to Java double"); type_t val = field(match.convert()); frame.SetDoubleField(c, fid, val); } void JPDoubleType::setArrayRange(JPJavaFrame& frame, jarray a, jsize start, jsize length, jsize step, PyObject* sequence) { JP_TRACE_IN("JPDoubleType::setArrayRange"); JPPrimitiveArrayAccessor accessor(frame, a, &JPJavaFrame::GetDoubleArrayElements, &JPJavaFrame::ReleaseDoubleArrayElements); type_t* val = accessor.get(); // First check if assigning sequence supports buffer API if (PyObject_CheckBuffer(sequence)) { JPPyBuffer buffer(sequence, PyBUF_FULL_RO); if (buffer.valid()) { Py_buffer& view = buffer.getView(); if (view.ndim != 1) JP_RAISE(PyExc_TypeError, "buffer dims incorrect"); Py_ssize_t vshape = view.shape[0]; Py_ssize_t vstep = view.strides[0]; if (vshape != length) JP_RAISE(PyExc_ValueError, "mismatched size"); char* memory = (char*) view.buf; if (view.suboffsets && view.suboffsets[0] >= 0) memory = *((char**) memory) + view.suboffsets[0]; jsize index = start; jconverter conv = getConverter(view.format, (int) view.itemsize, "d"); for (Py_ssize_t i = 0; i < length; ++i, index += step) { jvalue r = conv(memory); val[index] = r.d; memory += vstep; } accessor.commit(); return; } else { PyErr_Clear(); } } // Use sequence API JPPySequence seq = JPPySequence::use(sequence); jsize index = start; for (Py_ssize_t i = 0; i < length; ++i, index += step) { type_t v = (type_t) PyFloat_AsDouble(seq[i].get()); if (v == -1) JP_PY_CHECK(); val[index] = v; } accessor.commit(); JP_TRACE_OUT; } JPPyObject JPDoubleType::getArrayItem(JPJavaFrame& frame, jarray a, jsize ndx) { array_t array = (array_t) a; type_t val; frame.GetDoubleArrayRegion(array, ndx, 1, &val); jvalue v; field(v) = val; return convertToPythonObject(frame, v, false); } void JPDoubleType::setArrayItem(JPJavaFrame& frame, jarray a, jsize ndx, PyObject* obj) { JPMatch match(&frame, obj); if (findJavaConversion(match) < JPMatch::_implicit) JP_RAISE(PyExc_TypeError, "Unable to convert to Java double"); type_t val = field(match.convert()); frame.SetDoubleArrayRegion((array_t) a, ndx, 1, &val); } void JPDoubleType::getView(JPArrayView& view) { JPJavaFrame frame = JPJavaFrame::outer(view.getContext()); view.m_Memory = (void*) frame.GetDoubleArrayElements( (jdoubleArray) view.m_Array->getJava(), &view.m_IsCopy); view.m_Buffer.format = "d"; view.m_Buffer.itemsize = sizeof (jdouble); } void JPDoubleType::releaseView(JPArrayView& view) { try { JPJavaFrame frame = JPJavaFrame::outer(view.getContext()); frame.ReleaseDoubleArrayElements((jdoubleArray) view.m_Array->getJava(), (jdouble*) view.m_Memory, view.m_Buffer.readonly ? JNI_ABORT : 0); } catch (JPypeException&) { // This is called as part of the cleanup routine and exceptions // are not permitted } } const char* JPDoubleType::getBufferFormat() { return "d"; } ssize_t JPDoubleType::getItemSize() { return sizeof (jdouble); } void JPDoubleType::copyElements(JPJavaFrame &frame, jarray a, jsize start, jsize len, void* memory, int offset) { jdouble* b = (jdouble*) ((char*) memory + offset); frame.GetDoubleArrayRegion((jdoubleArray) a, start, len, b); } static void pack(jdouble* d, jvalue v) { *d = v.d; } PyObject *JPDoubleType::newMultiArray(JPJavaFrame &frame, JPPyBuffer &buffer, int subs, int base, jobject dims) { JP_TRACE_IN("JPDoubleType::newMultiArray"); return convertMultiArray( frame, this, &pack, "d", buffer, subs, base, dims); JP_TRACE_OUT; } jpype-1.3.0/native/common/jp_encoding.cpp000066400000000000000000000271521405671516700204260ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jp_encoding.h" // These encoders handle all of the codes expected to be passed between // Java and Python assuming they both generate complient codings. However, // this code does not handle miscodings very well. The current behavior // is to simply terminate the string at the bad code without producing // a warning. I can add errors, but I am not sure how I would test it // as both java and python will produce an error if I tried to force a // bad encoding on them. Thus I am going to leave this with the truncation // behavior for now. // // Examples of bad encodings: // - non-utf8 such as extended ascii passed from python // - encoded forbidden utf passed from python // - truncated surrogate codes passed from java // // The secondary problem is that string conversion is part of exception // handling. And the last thing we want to do is throw an exception // while trying to convert an exception string while reporting. That // would completely redirect the user. Thus truncation seems like // a sane policy unless we can verify all of the potential edge cases. // // Alternatively we could make them a bit more permissive and // try to automatically correct bad encodings by recognizing // extend ASCII, etc. But this is potentially complex and // has the downside that we can't test it currently. JPEncoding::~JPEncoding() { } // char* to stream from // https://stackoverflow.com/questions/7781898/get-an-istream-from-a-char struct membuf : std::streambuf { membuf(char* begin, char* end) { setg(begin, begin, end); } } ; // Convert a string from one encoding to another. // Currently we use this to transcribe from utf-8 to java-utf-8 and back. // It could do other encodings, but would need to be generalized to // a template to handle wider character sets. std::string transcribe(const char* in, size_t len, const JPEncoding& sourceEncoding, const JPEncoding& targetEncoding) { // ASCII bypass bool ascii = true; for (size_t i = 0; i < len; ++i) { if (in[i]&0x80 || in[i] == 0) { ascii = false; break; } } if (ascii) { return std::string(in, len); } // Convert input to istream source membuf sbuf(const_cast (in), const_cast (in + len)); std::istream inStream(&sbuf); // Create an output stream with reserve std::string out; out.reserve(len + 8); std::ostringstream outStream(out); while (!inStream.eof()) { unsigned int coding = sourceEncoding.fetch(inStream); if (coding == (unsigned int) - 1) { if (inStream.eof()) break; // Truncate bad strings for now. return outStream.str(); } targetEncoding.encode(outStream, coding); } return outStream.str(); } //************************************************************** // Encode a 21 bit code point as UTF-8 // // There are 4 encodings used // // Range Encoding // 0x000000-0x00007F // 0xxxxxxx // bits 6543210 // // 0x000080-0x0007FF // 110xxxxx 10xxxxxx // 1 // bits 09876 543210 // // 0x000800-0x000FFFF (excluding 0xD800-0xDFFF) // 1110xxxx 10xxxxxx 10xxxxxx // 1111 11 // bits 5432 109876 543210 // // 0x100000-0x10FFFF // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx // 211 111111 11 // bits 098 765432 109876 543210 // // The encoding process is simply to add the constant portion encoding // the byte position, then shifting to get the lowest bits, the masking // off the required bits. // void JPEncodingUTF8::encode(std::ostream& out, unsigned int c) const { if (c < 0x80) { // encode 1 out.put(char(c & 0xff)); } else if (c < 0x800) { // encode 2 out.put(char(0xc0 + ((c >> 6)&0x1f))); out.put(char(0x80 + ((c >> 0)&0x3f))); } else if (c < 0x10000) // Note 0xd800-0xdfff are not valid codes { // encode 3 out.put(char(0xe0 + ((c >> 12)&0x0f))); out.put(char(0x80 + ((c >> 6)&0x3f))); out.put(char(0x80 + ((c >> 0)&0x3f))); } else if (c < 0x110000) { // encode 4 out.put(char(0xf0 + ((c >> 18)&0x07))); out.put(char(0x80 + ((c >> 12)&0x3f))); out.put(char(0x80 + ((c >> 6)&0x3f))); out.put(char(0x80 + ((c >> 0)&0x3f))); } } // Retrieve a 21 unicode code point from a stream of bytes. // // This is the reverse of the process of encoding. // We must first locate the position encoding bits from the // top of the byte, then pull off the encoded bits. The // final code point is the sum of each set of encoded bits. // unsigned int JPEncodingUTF8::fetch(std::istream& in) const { unsigned int c0 = in.get(); if (in.eof()) return -1; // 1 byte code if ((c0 & 0x80) == 0) return c0; unsigned int c1 = in.get(); if (in.eof()) return -1; // 2 byte code if ((c0 & 0xe0) == 0xc0) { if ((c1 & 0xc0) == 0x80) return ((c0 & 0x1f) << 6) + (c1 & 0x3f); else return -1; // bad 2 byte format } unsigned int c2 = in.get(); if (in.eof()) return -1; // 3 byte code if ((c0 & 0xf0) == 0xe0) { if ((c1 & 0xc0) == 0x80 && (c2 & 0xc0) == 0x80) return ((c0 & 0xf) << 12) + ((c1 & 0x3f) << 6) + (c2 & 0x3f); return -1; } unsigned int c3 = in.get(); if (in.eof()) return -1; // 4 byte code if ((c0 & 0xf8) == 0xf0) { if ((c1 & 0xc0) == 0x80 && (c2 & 0xc0) == 0x80 && (c3 & 0xc0) == 0x80) return ((c0 & 0xf) << 18) + ((c1 & 0x3f) << 12) + ((c2 & 0x3f) << 6) + (c3 & 0x3f); return -1; } return -1; } // Encode a 21 code point into a Java UTF char stream. // // Java uses 16 bit characters to represent a string, but this is not // sufficient to hold all 21 bits of valid unicode chars. Thus to // encode the upper bits java uses UTF-16 encoding internally. Unfortunately, // when java converts the 16 bit string into 8 bit encoding, it does not // decode the string first. As a result we receive not UTF-8 but rather // doublely encoded UTF-16/UTF-8. Further UTF-16 encoding requires // not just simple byte packing but also an offset of the bits. Thus this // process becomes a real mess. Also a special code point is required for // embedded nulls. // // There are 4 encodings used // // Range Encoding // 0x000001-0x00007F // 0xxxxxxx // bits 6543210 // // 0x000080-0x0007FF, special code 0 // 110xxxxx 10xxxxxx // 1 // bits 09876 543210 // // 0x000800-0x000D7FF or 0x00DFFF-0x000FFFF // 1110xxxx 10xxxxxx 10xxxxxx // 1111 11 // bits 5432 109876 543210 // // 0x100000-0x10FFFF (called surgate codes in UTF-16) // (doublely encoded 6 byte code point) // first subtract 0x10000 which reduces the range by 2 bits // 11101101 1010xxxx 10xxxxxx 11101101 1011xxxx 10xxxxxx // 1111 111111 // bits 9876 543210 9876 543210 // // The encoding process is simply to add the constant portion encoding // the byte position, then shifting to get the lowest bits, the masking // off the required bits. The exception being the surgate codes which // require an offset then a bit pack. // // 4 byte unicode or coding a 3 point in the invalid range followed by anything other // than 3 byte encoding (in the invalid range) is a coding error. // void JPEncodingJavaUTF8::encode(std::ostream& out, unsigned int c) const { if (c == 0) { // encode 0 as 2 out.put(char(0xc0)); out.put(char(0x80)); } else if (c < 0x80) { // encode 1 out.put(char(c & 0xff)); } else if (c < 0x800) { // encode 2 out.put(char(0xc0 + ((c >> 6)&0x1f))); out.put(char(0x80 + ((c >> 0)&0x3f))); } else if (c < 0xd800 || (c >= 0xe000 && c < 0x10000)) { // encode 3 out.put(char(0xe0 + char((c >> 12)&0x0f))); out.put(char(0x80 + char((c >> 6)&0x3f))); out.put(char(0x80 + char((c >> 0)&0x3f))); } else if (c < 0x110000) { c = c - 0x10000; // encode 6 out.put(char(0xed)); out.put(char(0xa0 + ((c >> 16)&0xf))); out.put(char(0x80 + ((c >> 10)&0x3f))); out.put(char(0xed)); out.put(char(0xb0 + ((c >> 6)&0xf))); out.put(char(0x80 + ((c >> 0)&0x3f))); } } // Decoding is the reverse of encoding, but there // is a special gotcha because the position encoding bits // are not unique. Both the 3 and 6 points codes share // the position encoding 0xED for the first byte. // // The unicde packing solves this by removing a portion of // the encoding such that 0xD800-0xDFFF are not valid unicode code // points. Thus these invalid code points are used to represent // the upper and lower encoding for the extended unicode // code points. // // Thus the procedure is decode the top 3 and check to see if // it is in a valid range. If it isn't then decode the // second set of 3. So long as the bytes are coded through the // java encoder it will be valid. However, a user could // manually encode a string with an invalid coding. // unsigned int JPEncodingJavaUTF8::fetch(std::istream& in) const { unsigned int out = 0; unsigned int c0 = in.get(); if (in.eof()) return -1; if ((c0 & 0x80) == 0) return c0; unsigned int c1 = in.get(); if (in.eof()) return -1; if ((c0 & 0xe0) == 0xc0) { if ((c1 & 0xc0) == 0x80) return ((c0 & 0x1f) << 6) + (c1 & 0x3f); else return -1; // bad 2 byte format } unsigned int c2 = in.get(); if (in.eof()) return -1; if ((c0 & 0xf0) == 0xe0 && (c1 & 0xc0) == 0x80 && (c2 & 0xc0) == 0x80) { out = ((c0 & 0xf) << 12) + ((c1 & 0x3f) << 6) + (c2 & 0x3f); // 0xD800-0xDF00 are surrogate codes for 6 byte encoding // High code is 0xD800-0xDBFF, Low code is 0xDC00-0xDFFF // Plain old code if between 0x0000-0xD7FF, 0xE000-0xFFFF if ((out & 0xf800) != 0xd800) return out; } else { return -1; } // Surrogate code should be followed by 3 byte utf8 code unsigned int next = in.peek(); if (next == (unsigned int) (-1) || (next & 0xf0) != 0xe0) return out; // unpaired surrogate error. // Grab the low word for surrogate code c0 = in.get(); // Note: we should technically check to see what the first byte is here. // for a valid code point it must be 0xED. But if the user has // manually encoded an invalid string there is not much we can // do as we already are pulling bytes for the next character assuming // it was a valid coding. We don't really want to throw an exception // because this routine can happen at any point that string is being // passed, including reporting of an exception. // // Manually encoding invalid code points and asking them to be // converted is undefined behavior, but I don't know the path // to nethack. c1 = in.get(); c2 = in.get(); next = ((c0 & 0xf) << 12) + ((c1 & 0x3f) << 6) + (c2 & 0x3f); if (in.eof()) return -1; unsigned int q1 = (out & 0x3ff); unsigned int q2 = (next & 0x3ff); return 0x10000 + (q1 << 10) + q2; } jpype-1.3.0/native/common/jp_exception.cpp000066400000000000000000000433321405671516700206340ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include #include #include "jpype.h" #include "jp_exception.h" #include "pyjp.h" #include "jp_reference_queue.h" PyObject* PyTrace_FromJPStackTrace(JPStackTrace& trace); JPypeException::JPypeException(JPJavaFrame &frame, jthrowable th, const JPStackInfo& stackInfo) : m_Throwable(frame, th) { JP_TRACE("JAVA EXCEPTION THROWN with java throwable"); m_Context = frame.getContext(); m_Type = JPError::_java_error; m_Error.l = NULL; m_Message = frame.toString(th); from(stackInfo); } JPypeException::JPypeException(int type, void* error, const JPStackInfo& stackInfo) { JP_TRACE("EXCEPTION THROWN with error", error); m_Type = type; m_Error.l = error; m_Message = "None"; from(stackInfo); } JPypeException::JPypeException(int type, void* errType, const string& msn, const JPStackInfo& stackInfo) { JP_TRACE("EXCEPTION THROWN", errType, msn); m_Type = type; m_Error.l = errType; m_Message = msn; from(stackInfo); } // GCOVR_EXCL_START // This is only used during startup for OSError JPypeException::JPypeException(int type, const string& msn, int errType, const JPStackInfo& stackInfo) { JP_TRACE("EXCEPTION THROWN", errType, msn); m_Type = type; m_Error.i = errType; m_Message = msn; from(stackInfo); } JPypeException::JPypeException(const JPypeException& ex) : m_Context(ex.m_Context), m_Trace(ex.m_Trace), m_Throwable(ex.m_Throwable) { m_Type = ex.m_Type; m_Error = ex.m_Error; m_Message = ex.m_Message; } JPypeException& JPypeException::operator = (const JPypeException& ex) { m_Context = ex.m_Context; m_Type = ex.m_Type; m_Trace = ex.m_Trace; m_Throwable = ex.m_Throwable; m_Error = ex.m_Error; m_Message = ex.m_Message; return *this; } // GCOVR_EXCL_STOP JPypeException::~JPypeException() { } void JPypeException::from(const JPStackInfo& info) { JP_TRACE("EXCEPTION FROM: ", info.getFile(), info.getLine()); m_Trace.push_back(info); } // Okay from this point on we have to suit up in full Kevlar because // this code must handle every conceivable and still reach a resolution. // Exceptions may be throws during initialization where only a fraction // of the resources are available, during the middle of normal operation, // or worst of all as the system is being yanked out from under us during // shutdown. Each and every one of these cases must be considered. // Further each and every function called here must be hardened similarly // or they will become the weak link. And remember it is not paranoia if // they are actually out to get you. // // Onward my friends to victory or a glorious segfault! string JPypeException::getMessage() { JP_TRACE_IN("JPypeException::getMessage"); // Must be bullet proof try { stringstream str; str << m_Message << endl; JP_TRACE(str.str()); return str.str(); // GCOVR_EXCL_START } catch (...) { return "error during get message"; } JP_TRACE_OUT; // GCOVR_EXCL_STOP } bool isJavaThrowable(PyObject* exceptionClass) { JPClass* cls = PyJPClass_getJPClass(exceptionClass); if (cls == NULL) return false; return cls->isThrowable(); } void JPypeException::convertJavaToPython() { // Welcome to paranoia land, where they really are out to get you! JP_TRACE_IN("JPypeException::convertJavaToPython"); // GCOVR_EXCL_START if (m_Context == NULL) { PyErr_SetString(PyExc_RuntimeError, "Unable to convert java error, context is null."); return; } // GCOVR_EXCL_STOP // Okay we can get to a frame to talk to the object JPJavaFrame frame = JPJavaFrame::external(m_Context, m_Context->getEnv()); jthrowable th = m_Throwable.get(); jvalue v; v.l = th; // GCOVR_EXCL_START // This is condition is only hit if something fails during the initial boot if (m_Context->getJavaContext() == NULL || m_Context->m_Context_GetExcClassID == NULL) { PyErr_SetString(PyExc_SystemError, frame.toString(th).c_str()); return; } // GCOVR_EXCL_STOP jlong pycls = frame.CallLongMethodA(m_Context->getJavaContext(), m_Context->m_Context_GetExcClassID, &v); if (pycls != 0) { jlong value = frame.CallLongMethodA(m_Context->getJavaContext(), m_Context->m_Context_GetExcValueID, &v); PyErr_SetObject((PyObject*) pycls, (PyObject*) value); return; } JP_TRACE("Check typemanager"); // GCOVR_EXCL_START if (!m_Context->isRunning()) { PyErr_SetString(PyExc_RuntimeError, frame.toString((jobject) th).c_str()); return; } // GCOVR_EXCL_STOP // Convert to Python object JP_TRACE("Convert to python"); JPClass* cls = frame.findClassForObject((jobject) th); // GCOVR_EXCL_START // This sanity check can only fail if the type system fails to find a // class for the current exception. if (cls == NULL) { // Nope, no class found PyErr_SetString(PyExc_RuntimeError, frame.toString(th).c_str()); return; } // GCOVR_EXCL_STOP // Create the exception object (this may fail) v.l = th; JPPyObject pyvalue = cls->convertToPythonObject(frame, v, false); // GCOVR_EXCL_START // This sanity check can only be hit if the exception failed during // conversion in some extraordinary way. if (pyvalue.isNull()) { PyErr_SetString(PyExc_RuntimeError, frame.toString(th).c_str()); return; } // GCOVR_EXCL_STOP PyObject *type = (PyObject*) Py_TYPE(pyvalue.get()); Py_INCREF(type); // Add cause to the exception JPPyObject args = JPPyObject::call(Py_BuildValue("(s)", "Java Exception")); JPPyObject cause = JPPyObject::call(PyObject_Call(PyExc_Exception, args.get(), NULL)); JPPyObject trace = PyTrace_FromJavaException(frame, th, NULL); // Attach Java causes as well. try { jthrowable jcause = frame.getCause(th); if (jcause != NULL) { jvalue a; a.l = (jobject) jcause; JPPyObject prev = frame.getContext()->_java_lang_Object->convertToPythonObject(frame, a, false); PyJPException_normalize(frame, prev, jcause, th); PyException_SetCause(cause.get(), prev.keep()); } PyException_SetTraceback(cause.get(), trace.get()); PyException_SetCause(pyvalue.get(), cause.keep()); } catch (JPypeException& ex) { JP_TRACE("FAILURE IN CAUSE"); // Any failures in this optional action should be ignored. // worst case we don't print as much diagnostics. } // Transfer to Python PyErr_SetObject(type, pyvalue.get()); JP_TRACE_OUT; // GCOVR_EXCL_LINE } void JPypeException::convertPythonToJava(JPContext* context) { JP_TRACE_IN("JPypeException::convertPythonToJava"); JPJavaFrame frame = JPJavaFrame::outer(context); jthrowable th; JPPyErrFrame eframe; if (eframe.good && isJavaThrowable(eframe.m_ExceptionClass.get())) { eframe.good = false; JPValue* javaExc = PyJPValue_getJavaSlot(eframe.m_ExceptionValue.get()); if (javaExc != NULL) { th = (jthrowable) javaExc->getJavaObject(); JP_TRACE("Throwing Java", frame.toString(th)); frame.Throw(th); return; } } if (context->m_Context_CreateExceptionID == NULL) { frame.ThrowNew(frame.FindClass("java/lang/RuntimeException"), getMessage().c_str()); return; } // Otherwise jvalue v[2]; v[0].j = (jlong) eframe.m_ExceptionClass.get(); v[1].j = (jlong) eframe.m_ExceptionValue.get(); th = (jthrowable) frame.CallObjectMethodA(context->getJavaContext(), context->m_Context_CreateExceptionID, v); frame.registerRef((jobject) th, eframe.m_ExceptionClass.get()); frame.registerRef((jobject) th, eframe.m_ExceptionValue.get()); eframe.clear(); frame.Throw(th); JP_TRACE_OUT; // GCOVR_EXCL_LINE } int JPError::_java_error = 1; int JPError::_python_error = 2; int JPError::_python_exc = 3; int JPError::_os_error_unix = 10; int JPError::_os_error_windows = 11; int JPError::_method_not_found = 20; void JPypeException::toPython() { string mesg; JP_TRACE_IN("JPypeException::toPython"); try { // Check the signals before processing the exception // It may be a signal when interrupted Java in which case // the signal takes precedence. if (PyErr_CheckSignals()!=0) return; mesg = getMessage(); JP_TRACE(m_Error.l); JP_TRACE(mesg.c_str()); if (m_Type == JPError::_java_error) { JP_TRACE("Java exception"); JPypeException::convertJavaToPython(); return; } else if (m_Type == JPError::_python_error) { // Already on the stack } else if (m_Type == JPError::_method_not_found) { // This is hit when a proxy fails to implement a required // method. Only older style proxies should be able hit this. JP_TRACE("Runtime error"); PyErr_SetString(PyExc_RuntimeError, mesg.c_str()); }// This section is only reachable during startup of the JVM. // GCOVR_EXCL_START else if (m_Type == JPError::_os_error_unix) { std::stringstream ss; ss << "JVM DLL not found: " << mesg; PyObject* val = Py_BuildValue("(iz)", m_Error.i, ss.str().c_str()); if (val != NULL) { PyObject* exc = PyObject_Call(PyExc_OSError, val, NULL); Py_DECREF(val); if (exc != NULL) { PyErr_SetObject(PyExc_OSError, exc); Py_DECREF(exc); } } } else if (m_Type == JPError::_os_error_windows) { std::stringstream ss; ss << "JVM DLL not found: " << mesg; PyObject* val = Py_BuildValue("(izzi)", 2, ss.str().c_str(), NULL, m_Error.i); if (val != NULL) { PyObject* exc = PyObject_Call(PyExc_OSError, val, NULL); Py_DECREF(val); if (exc != NULL) { PyErr_SetObject(PyExc_OSError, exc); Py_DECREF(exc); } } }// GCOVR_EXCL_STOP else if (m_Type == JPError::_python_exc) { // All others are Python errors JP_TRACE(Py_TYPE(m_Error.l)->tp_name); PyErr_SetString((PyObject*) m_Error.l, mesg.c_str()); } else { // This should not be possible unless we failed to cover one of the // exception type codes. JP_TRACE("Unknown error"); PyErr_SetString(PyExc_RuntimeError, mesg.c_str()); // GCOVR_EXCL_LINE } // Attach our info as the cause if (_jp_cpp_exceptions) { JPPyErrFrame eframe; eframe.normalize(); JPPyObject args = JPPyObject::call(Py_BuildValue("(s)", "C++ Exception")); JPPyObject trace = JPPyObject::call(PyTrace_FromJPStackTrace(m_Trace)); JPPyObject cause = JPPyObject::accept(PyObject_Call(PyExc_Exception, args.get(), NULL)); if (!cause.isNull()) { PyException_SetTraceback(cause.get(), trace.get()); PyException_SetCause(eframe.m_ExceptionValue.get(), cause.keep()); } } }// GCOVR_EXCL_START catch (JPypeException& ex) { // Print our parting words JPTracer::trace("Fatal error in exception handling"); JPTracer::trace("Handling:", mesg); JPTracer::trace("Type:", m_Error.l); if (ex.m_Type == JPError::_python_error) { JPPyErrFrame eframe; JPTracer::trace("Inner Python:", ((PyTypeObject*) eframe.m_ExceptionClass.get())->tp_name); return; // Let these go to Python so we can see the error } else if (ex.m_Type == JPError::_java_error) JPTracer::trace("Inner Java:", ex.getMessage()); else JPTracer::trace("Inner:", ex.getMessage()); JPStackInfo info = ex.m_Trace.front(); JPTracer::trace(info.getFile(), info.getFunction(), info.getLine()); // Heghlu'meH QaQ jajvam! PyErr_SetString(PyExc_RuntimeError, "Fatal error occurred"); return; } catch (...) { // urp?! JPTracer::trace("Fatal error in exception handling"); // You shall not pass! int *i = 0; *i = 0; } // GCOVR_EXCL_STOP JP_TRACE_OUT; // GCOVR_EXCL_LINE } void JPypeException::toJava(JPContext *context) { JP_TRACE_IN("JPypeException::toJava"); try { string mesg = getMessage(); JPJavaFrame frame = JPJavaFrame::external(context, context->getEnv()); if (m_Type == JPError::_java_error) { JP_TRACE("Java exception"); //JP_TRACE(context->toString((jobject) frame.ExceptionOccurred())); if (m_Throwable.get() != 0) { JP_TRACE("Java rethrow"); frame.Throw(m_Throwable.get()); return; } return; } if (m_Type == JPError::_method_not_found) { frame.ThrowNew(context->m_NoSuchMethodError.get(), mesg.c_str()); return; } if (m_Type == JPError::_python_error) { JPPyCallAcquire callback; JP_TRACE("Python exception"); convertPythonToJava(context); return; } if (m_Type == JPError::_python_exc) { JPPyCallAcquire callback; // All others are Python errors JP_TRACE(Py_TYPE(m_Error.l)->tp_name); PyErr_SetString((PyObject*) m_Error.l, mesg.c_str()); convertPythonToJava(context); return; } // All others are issued as RuntimeExceptions JP_TRACE("String exception"); frame.ThrowNew(context->m_RuntimeException.get(), mesg.c_str()); return; } catch (JPypeException& ex) // GCOVR_EXCL_LINE { // GCOVR_EXCL_START // Print our parting words. JPTracer::trace("Fatal error in exception handling"); JPStackInfo info = ex.m_Trace.front(); JPTracer::trace(info.getFile(), info.getFunction(), info.getLine()); // Take one for the team. int *i = 0; *i = 0; // GCOVR_EXCL_STOP } catch (...) // GCOVR_EXCL_LINE { // GCOVR_EXCL_START // urp?! JPTracer::trace("Fatal error in exception handling"); // It is pointless, I can't go on. int *i = 0; *i = 0; // GCOVR_EXCL_STOP } JP_TRACE_OUT; // GCOVR_EXCL_LINE } PyTracebackObject *tb_create( PyTracebackObject *last_traceback, PyObject *dict, const char* filename, const char* funcname, int linenum) { // Create a code for this frame. (ref count is 1) PyCodeObject *code = PyCode_NewEmpty(filename, funcname, linenum); // If we don't get the code object there is no point if (code == NULL) return NULL; // This is a bit of a kludge. Python lacks a way to directly create // a frame from a code object except when creating from the threadstate. // // In reviewing Python implementation, I find that the only element accessed // in the thread state was the previous frame to link to. Because frame // objects change a lot between different Python versions, trying to // replicate the actions of setting up a frame is difficult to keep portable. // // Python 3.10 introduces the additional requirement that the global // dictionary supplied must have a __builtins__. We can do this once // when create the module. // // If instead we create a thread state and point the field it needs to the // previous frame we create the frames using the defined API. Much more // portable, but we have to create a big (uninitialized object) each time we // want to pass in the previous frame. PyThreadState state; if (last_traceback != NULL) state.frame = last_traceback->tb_frame; else state.frame = NULL; // Create a frame for the traceback. PyFrameObject *frame = PyFrame_New(&state, code, dict, NULL); // frame just borrows the reference rather than claiming it // so we need to get rid of the extra reference here. Py_DECREF(code); // If we don't get the frame object there is no point if (frame == NULL) return NULL; // Create a traceback PyTracebackObject *traceback = (PyTracebackObject*) PyObject_GC_New(PyTracebackObject, &PyTraceBack_Type); // We could fail in process if (traceback == NULL) { Py_DECREF(frame); return NULL; } // Set the fields traceback->tb_frame = frame; // Steal the reference from frame traceback->tb_lasti = frame->f_lasti; traceback->tb_lineno = linenum; Py_XINCREF(last_traceback); traceback->tb_next = last_traceback; // Allow GC on the object PyObject_GC_Track(traceback); return traceback; } PyObject* PyTrace_FromJPStackTrace(JPStackTrace& trace) { PyTracebackObject *last_traceback = NULL; PyObject *dict = PyModule_GetDict(PyJPModule); for (JPStackTrace::iterator iter = trace.begin(); iter != trace.end(); ++iter) { last_traceback = tb_create(last_traceback, dict, iter->getFile(), iter->getFunction(), iter->getLine()); } if (last_traceback == NULL) Py_RETURN_NONE; return (PyObject*) last_traceback; } JPPyObject PyTrace_FromJavaException(JPJavaFrame& frame, jthrowable th, jthrowable prev) { PyTracebackObject *last_traceback = NULL; JPContext *context = frame.getContext(); jvalue args[2]; args[0].l = th; args[1].l = prev; if (context->m_Context_GetStackFrameID == NULL) return JPPyObject(); JNIEnv* env = frame.getEnv(); jobjectArray obj = (jobjectArray) env->CallObjectMethodA(context->getJavaContext(), context->m_Context_GetStackFrameID, args); // Eat any exceptions that were generated if (env->ExceptionCheck() == JNI_TRUE) env->ExceptionClear(); if (obj == NULL) return JPPyObject(); jsize sz = frame.GetArrayLength(obj); PyObject *dict = PyModule_GetDict(PyJPModule); for (jsize i = 0; i < sz; i += 4) { string filename, method; jstring jclassname = (jstring) frame.GetObjectArrayElement(obj, i); jstring jmethodname = (jstring) frame.GetObjectArrayElement(obj, i + 1); jstring jfilename = (jstring) frame.GetObjectArrayElement(obj, i + 2); if (jfilename != NULL) filename = frame.toStringUTF8(jfilename); else filename = frame.toStringUTF8(jclassname) + ".java"; if (jmethodname != NULL) method = frame.toStringUTF8(jclassname) + "." + frame.toStringUTF8(jmethodname); jint lineNum = frame.CallIntMethodA(frame.GetObjectArrayElement(obj, i + 3), context->_java_lang_Integer->m_IntValueID, 0); last_traceback = tb_create(last_traceback, dict, filename.c_str(), method.c_str(), lineNum); frame.DeleteLocalRef(jclassname); frame.DeleteLocalRef(jmethodname); frame.DeleteLocalRef(jfilename); } if (last_traceback == NULL) return JPPyObject(); return JPPyObject::call((PyObject*) last_traceback); } jpype-1.3.0/native/common/jp_field.cpp000066400000000000000000000040531405671516700177160ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "jp_field.h" JPField::JPField(JPJavaFrame& frame, JPClass* cls, const string& name, jobject field, jfieldID fid, JPClass* fieldType, jint modifiers) : m_Field(frame, field) { m_Class = cls; m_Name = name; m_FieldID = fid; m_Type = fieldType; m_Modifiers = modifiers; } JPField::~JPField() { } JPPyObject JPField::getStaticField() { JP_TRACE_IN("JPField::getStaticAttribute"); JPJavaFrame frame = JPJavaFrame::outer(m_Class->getContext()); return m_Type->getStaticField(frame, m_Class->getJavaClass(), m_FieldID); JP_TRACE_OUT; } void JPField::setStaticField(PyObject *pyobj) { JP_TRACE_IN("JPField::setStaticAttribute"); JPJavaFrame frame = JPJavaFrame::outer(m_Class->getContext()); m_Type->setStaticField(frame, m_Class->getJavaClass(), m_FieldID, pyobj); JP_TRACE_OUT; } JPPyObject JPField::getField(jobject inst) { JP_TRACE_IN("JPField::getAttribute"); JPJavaFrame frame = JPJavaFrame::outer(m_Class->getContext()); ASSERT_NOT_NULL(m_Type); JP_TRACE("field type", m_Type->getCanonicalName()); return m_Type->getField(frame, inst, m_FieldID); JP_TRACE_OUT; } void JPField::setField(jobject inst, PyObject *pyobj) { JP_TRACE_IN("JPField::setAttribute"); JPJavaFrame frame = JPJavaFrame::outer(m_Class->getContext()); m_Type->setField(frame, inst, m_FieldID, pyobj); JP_TRACE_OUT; } jpype-1.3.0/native/common/jp_floattype.cpp000066400000000000000000000222621405671516700206440ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "pyjp.h" #include "jp_array.h" #include "jp_primitive_accessor.h" #include "jp_floattype.h" #include "jp_boxedtype.h" JPFloatType::JPFloatType() : JPPrimitiveType("float") { } JPFloatType::~JPFloatType() { } JPPyObject JPFloatType::convertToPythonObject(JPJavaFrame& frame, jvalue value, bool cast) { PyTypeObject * wrapper = getHost(); JPPyObject obj = JPPyObject::call(wrapper->tp_alloc(wrapper, 0)); ((PyFloatObject*) obj.get())->ob_fval = value.f; PyJPValue_assignJavaSlot(frame, obj.get(), JPValue(this, value)); return obj; } JPValue JPFloatType::getValueFromObject(const JPValue& obj) { JPContext *context = obj.getClass()->getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); jvalue v; jobject jo = obj.getValue().l; JPBoxedType* jb = (JPBoxedType*) frame.findClassForObject(jo); field(v) = (type_t) frame.CallFloatMethodA(jo, jb->m_FloatValueID, 0); return JPValue(this, v); } static JPConversionAsFloat asFloatConversion; static JPConversionLongAsFloat asFloatLongConversion; static JPConversionFloatWiden floatWidenConversion; class JPConversionAsJFloat : public JPConversionJavaValue { public: virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) override { JPValue *value = match.getJavaSlot(); if (value == NULL) return match.type = JPMatch::_none; match.type = JPMatch::_none; // Implied conversion from boxed to primitive (JLS 5.1.8) if (javaValueConversion->matches(cls, match) || unboxConversion->matches(cls, match)) return match.type; // Consider widening JPClass *cls2 = value->getClass(); if (cls2->isPrimitive()) { // https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.2 JPPrimitiveType *prim = (JPPrimitiveType*) cls2; switch (prim->getTypeCode()) { case 'B': case 'S': case 'C': case 'I': case 'J': match.conversion = &floatWidenConversion; return match.type = JPMatch::_implicit; default: break; } } // Unboxing must be to the from the exact boxed type (JLS 5.1.8) return JPMatch::_implicit; // stop search } virtual void getInfo(JPClass *cls, JPConversionInfo &info) override { JPContext *context = cls->getContext(); PyList_Append(info.exact, (PyObject*) context->_float->getHost()); PyList_Append(info.implicit, (PyObject*) context->_byte->getHost()); PyList_Append(info.implicit, (PyObject*) context->_char->getHost()); PyList_Append(info.implicit, (PyObject*) context->_short->getHost()); PyList_Append(info.implicit, (PyObject*) context->_int->getHost()); PyList_Append(info.implicit, (PyObject*) context->_long->getHost()); unboxConversion->getInfo(cls, info); } } asJFloatConversion; JPMatch::Type JPFloatType::findJavaConversion(JPMatch &match) { JP_TRACE_IN("JPFloatType::findJavaConversion"); if (match.object == Py_None) return match.type = JPMatch::_none; if (asJFloatConversion.matches(this, match) || asFloatLongConversion.matches(this, match) || asFloatConversion.matches(this, match)) return match.type; return match.type = JPMatch::_none; JP_TRACE_OUT; } void JPFloatType::getConversionInfo(JPConversionInfo &info) { JPJavaFrame frame = JPJavaFrame::outer(m_Context); asJFloatConversion.getInfo(this, info); asFloatLongConversion.getInfo(this, info); asFloatConversion.getInfo(this, info); PyList_Append(info.ret, (PyObject*) m_Context->_float->getHost()); } jarray JPFloatType::newArrayOf(JPJavaFrame& frame, jsize sz) { return frame.NewFloatArray(sz); } JPPyObject JPFloatType::getStaticField(JPJavaFrame& frame, jclass c, jfieldID fid) { jvalue v; field(v) = frame.GetStaticFloatField(c, fid); return convertToPythonObject(frame, v, false); } JPPyObject JPFloatType::getField(JPJavaFrame& frame, jobject c, jfieldID fid) { jvalue v; field(v) = frame.GetFloatField(c, fid); return convertToPythonObject(frame, v, false); } JPPyObject JPFloatType::invokeStatic(JPJavaFrame& frame, jclass claz, jmethodID mth, jvalue *val) { jvalue v; { JPPyCallRelease call; field(v) = frame.CallStaticFloatMethodA(claz, mth, val); } return convertToPythonObject(frame, v, false); } JPPyObject JPFloatType::invoke(JPJavaFrame& frame, jobject obj, jclass clazz, jmethodID mth, jvalue *val) { jvalue v; { JPPyCallRelease call; if (clazz == NULL) field(v) = frame.CallFloatMethodA(obj, mth, val); else field(v) = frame.CallNonvirtualFloatMethodA(obj, clazz, mth, val); } return convertToPythonObject(frame, v, false); } void JPFloatType::setStaticField(JPJavaFrame& frame, jclass c, jfieldID fid, PyObject *obj) { JPMatch match(&frame, obj); if (findJavaConversion(match) < JPMatch::_implicit) JP_RAISE(PyExc_TypeError, "Unable to convert to Java float"); type_t val = field(match.convert()); frame.SetStaticFloatField(c, fid, val); } void JPFloatType::setField(JPJavaFrame& frame, jobject c, jfieldID fid, PyObject *obj) { JPMatch match(&frame, obj); if (findJavaConversion(match) < JPMatch::_implicit) JP_RAISE(PyExc_TypeError, "Unable to convert to Java float"); type_t val = field(match.convert()); frame.SetFloatField(c, fid, val); } void JPFloatType::setArrayRange(JPJavaFrame& frame, jarray a, jsize start, jsize length, jsize step, PyObject* sequence) { JP_TRACE_IN("JPFloatType::setArrayRange"); JPPrimitiveArrayAccessor accessor(frame, a, &JPJavaFrame::GetFloatArrayElements, &JPJavaFrame::ReleaseFloatArrayElements); type_t* val = accessor.get(); // First check if assigning sequence supports buffer API if (PyObject_CheckBuffer(sequence)) { JPPyBuffer buffer(sequence, PyBUF_FULL_RO); if (buffer.valid()) { Py_buffer& view = buffer.getView(); if (view.ndim != 1) JP_RAISE(PyExc_TypeError, "buffer dims incorrect"); Py_ssize_t vshape = view.shape[0]; Py_ssize_t vstep = view.strides[0]; if (vshape != length) JP_RAISE(PyExc_ValueError, "mismatched size"); char* memory = (char*) view.buf; if (view.suboffsets && view.suboffsets[0] >= 0) memory = *((char**) memory) + view.suboffsets[0]; jsize index = start; jconverter conv = getConverter(view.format, (int) view.itemsize, "f"); for (Py_ssize_t i = 0; i < length; ++i, index += step) { jvalue r = conv(memory); val[index] = r.f; memory += vstep; } accessor.commit(); return; } else { PyErr_Clear(); } } // Use sequence API JPPySequence seq = JPPySequence::use(sequence); jsize index = start; for (Py_ssize_t i = 0; i < length; ++i, index += step) { double v = PyFloat_AsDouble(seq[i].get()); if (v == -1.) JP_PY_CHECK(); val[index] = (type_t) v; } accessor.commit(); JP_TRACE_OUT; } JPPyObject JPFloatType::getArrayItem(JPJavaFrame& frame, jarray a, jsize ndx) { array_t array = (array_t) a; type_t val; frame.GetFloatArrayRegion(array, ndx, 1, &val); jvalue v; field(v) = val; return convertToPythonObject(frame, v, false); } void JPFloatType::setArrayItem(JPJavaFrame& frame, jarray a, jsize ndx, PyObject* obj) { JPMatch match(&frame, obj); if (findJavaConversion(match) < JPMatch::_implicit) JP_RAISE(PyExc_TypeError, "Unable to convert to Java float"); type_t val = field(match.convert()); frame.SetFloatArrayRegion((array_t) a, ndx, 1, &val); } void JPFloatType::getView(JPArrayView& view) { JPJavaFrame frame = JPJavaFrame::outer(view.getContext()); view.m_Memory = (void*) frame.GetFloatArrayElements( (jfloatArray) view.m_Array->getJava(), &view.m_IsCopy); view.m_Buffer.format = "f"; view.m_Buffer.itemsize = sizeof (jfloat); } void JPFloatType::releaseView(JPArrayView& view) { try { JPJavaFrame frame = JPJavaFrame::outer(view.getContext()); frame.ReleaseFloatArrayElements((jfloatArray) view.m_Array->getJava(), (jfloat*) view.m_Memory, view.m_Buffer.readonly ? JNI_ABORT : 0); } catch (JPypeException&) { // This is called as part of the cleanup routine and exceptions // are not permitted } } const char* JPFloatType::getBufferFormat() { return "f"; } ssize_t JPFloatType::getItemSize() { return sizeof (jfloat); } void JPFloatType::copyElements(JPJavaFrame &frame, jarray a, jsize start, jsize len, void* memory, int offset) { jfloat* b = (jfloat*) ((char*) memory + offset); frame.GetFloatArrayRegion((jfloatArray) a, start, len, b); } static void pack(jfloat* d, jvalue v) { *d = v.f; } PyObject *JPFloatType::newMultiArray(JPJavaFrame &frame, JPPyBuffer &buffer, int subs, int base, jobject dims) { JP_TRACE_IN("JPFloatType::newMultiArray"); return convertMultiArray( frame, this, &pack, "f", buffer, subs, base, dims); JP_TRACE_OUT; } jpype-1.3.0/native/common/jp_functional.cpp000066400000000000000000000056221405671516700210000ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "pyjp.h" #include "jp_functional.h" #include "jp_proxy.h" JPFunctional::JPFunctional(JPJavaFrame& frame, jclass clss, const string& name, JPClass* super, JPClassList& interfaces, jint modifiers) : JPClass(frame, clss, name, super, interfaces, modifiers) { m_Method = frame.getFunctional(clss); } JPFunctional::~JPFunctional() { } class JPConversionFunctional : public JPConversion { public: virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) override { if (!PyCallable_Check(match.object)) return match.type = JPMatch::_none; match.conversion = this; match.closure = cls; return match.type = JPMatch::_implicit; } virtual void getInfo(JPClass *cls, JPConversionInfo &info) override { PyObject *typing = PyImport_AddModule("jpype.protocol"); JPPyObject proto = JPPyObject::call(PyObject_GetAttrString(typing, "Callable")); PyList_Append(info.implicit, proto.get()); } virtual jvalue convert(JPMatch &match) override { JPFunctional *cls = (JPFunctional*) match.closure; JP_TRACE_IN("JPConversionFunctional::convert"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::inner(context); PyJPProxy *self = (PyJPProxy*) PyJPProxy_Type->tp_alloc(PyJPProxy_Type, 0); JP_PY_CHECK(); JPClassList cl; cl.push_back(cls); self->m_Proxy = new JPProxyFunctional(context, self, cl); self->m_Target = match.object; self->m_Convert = true; Py_INCREF(match.object); jvalue v = self->m_Proxy->getProxy(); v.l = frame.keep(v.l); Py_DECREF(self); return v; JP_TRACE_OUT; // GCOVR_EXCL_LINE } } functional_conversion; JPMatch::Type JPFunctional::findJavaConversion(JPMatch &match) { JP_TRACE_IN("JPJPFunctional::findJavaConversiocdn"); JPClass::findJavaConversion(match); if (match.type != JPMatch::_none) return match.type; if (functional_conversion.matches(this, match)) return match.type; return match.type = JPMatch::_none; JP_TRACE_OUT; // GCOVR_EXCL_LINE } void JPFunctional::getConversionInfo(JPConversionInfo &info) { JP_TRACE_IN("JPJPFunctional::getConversionInfo"); JPClass::getConversionInfo(info); functional_conversion.getInfo(this, info); JP_TRACE_OUT; // GCOVR_EXCL_LINE } jpype-1.3.0/native/common/jp_gc.cpp000066400000000000000000000141421405671516700172240ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include #include "jpype.h" #include "pyjp.h" #include "jp_reference_queue.h" #include "jp_gc.h" #ifdef WIN32 #define USE_PROCESS_INFO #include #include #elif __APPLE__ #define USE_TASK_INFO #include #include #include #elif __GLIBC__ // Linux doesn't have an available rss tally so use mallinfo #define USE_MALLINFO #include #elif __linux__ #define USE_PROC_INFO #include #include #include #include static int statm_fd; static int page_size; #else #define USE_NONE #endif #define DELTA_LIMIT 20*1024*1024l size_t getWorkingSize() { size_t current = 0; #if defined(USE_PROCESS_INFO) PROCESS_MEMORY_COUNTERS pmc; GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof (pmc)); current = (size_t) pmc.WorkingSetSize; #elif defined(USE_TASK_INFO) struct mach_task_basic_info info; mach_msg_type_number_t count = MACH_TASK_BASIC_INFO_COUNT; if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t) & info, &count) == KERN_SUCCESS) current = (size_t) info.resident_size; #elif defined(USE_PROC_INFO) char bytes[32]; lseek(statm_fd, SEEK_SET, 0); int len = read(statm_fd, bytes, 32); long long sz = 0; int i = 0; for (; i < len; i++) { if (bytes[i] == ' ') break; } i++; for (; i < len; i++) { if (bytes[i] == ' ') return sz * page_size; sz *= 10; sz += bytes[i] - '0'; } return sz * page_size; #elif defined(USE_MALLINFO) struct mallinfo mi; mi = mallinfo(); current = (size_t) mi.uordblks; #endif return current; } void triggerPythonGC(); void JPGarbageCollection::triggered() { // If we were triggered from Java call a Python cleanup if (!in_python_gc) { // trigger Python gc in_python_gc = true; java_triggered = true; java_count++; // Lock Python so we call trigger a GC JPPyCallAcquire callback; PyGC_Collect(); } } JPGarbageCollection::JPGarbageCollection(JPContext *context) { m_Context = context; running = false; in_python_gc = false; java_triggered = false; python_gc = NULL; _SystemClass = NULL; _gcMethodID = NULL; last_python = 0; last_java = 0; low_water = 0; high_water = 0; limit = 0; last = 0; java_count = 0; python_count = 0; python_triggered = 0; } void JPGarbageCollection::init(JPJavaFrame& frame) { #if defined(USE_PROC_INFO) statm_fd = open("/proc/self/statm", O_RDONLY); page_size = getpagesize(); #endif // Get the Python garbage collector JPPyObject gc = JPPyObject::call(PyImport_ImportModule("gc")); python_gc = gc.keep(); // Find the callbacks JPPyObject callbacks = JPPyObject::call(PyObject_GetAttrString(python_gc, "callbacks")); // Hook up our callback JPPyObject collect = JPPyObject::call(PyObject_GetAttrString(PyJPModule, "_collect")); PyList_Append(callbacks.get(), collect.get()); JP_PY_CHECK(); // Get the Java System gc so we can trigger _SystemClass = (jclass) frame.NewGlobalRef(frame.FindClass("java/lang/System")); _gcMethodID = frame.GetStaticMethodID(_SystemClass, "gc", "()V"); running = true; high_water = getWorkingSize(); limit = high_water + DELTA_LIMIT; } void JPGarbageCollection::shutdown() { running = false; #if defined(USE_PROC_INFO) close(statm_fd); #endif } void JPGarbageCollection::onStart() { // GCOVR_EXCL_START // GC is triggered outside of user control. Including it in // coverage just creates random statistics. if (!running) return; getWorkingSize(); in_python_gc = true; // GCOVR_EXCL_STOP } void JPGarbageCollection::onEnd() { // GCOVR_EXCL_START // GC is triggered outside of user control. Including it in // coverage just creates random statistics. if (!running) return; if (java_triggered) { // Remove our lock so that we can watch for triggers java_triggered = false; return; } if (in_python_gc) { in_python_gc = false; python_count++; int run_gc = 0; size_t current = getWorkingSize(); if (current > high_water) high_water = current; if (current < low_water) low_water = current; if (java_triggered) last_java = current; else last_python = current; // Things are getting better so use high water as limit if (current == low_water) { limit = (limit + high_water) / 2; if ( high_water > low_water + 4 * DELTA_LIMIT) high_water = low_water + 4 * DELTA_LIMIT; } if (last_python > current) last_python = current; if (current < last) { last = current; return; } // Decide the policy if (current > limit) { limit = high_water + DELTA_LIMIT; run_gc = 1; } // Predict if we will cross the limit soon. ssize_t pred = current + 2 * (current - last); last = current; if ((ssize_t) pred > (ssize_t) limit) run_gc = 2; // printf("consider gc %d (%ld, %ld, %ld, %ld) %ld\n", run_gc, // current, low_water, high_water, limit, limit - pred); if (run_gc > 0) { // Move up the low water low_water = (low_water + high_water) / 2; // Don't reset the limit if it was count triggered JPJavaFrame frame = JPJavaFrame::outer(m_Context); frame.CallStaticVoidMethodA(_SystemClass, _gcMethodID, 0); python_triggered++; } } // GCOVR_EXCL_STOP } void JPGarbageCollection::getStats(JPGCStats& stats) { // GCOVR_EXCL_START stats.current_rss = getWorkingSize(); stats.min_rss = low_water; stats.max_rss = high_water; stats.java_rss = last_java; stats.python_rss = last_python; stats.python_triggered = python_triggered; // GCOVR_EXCL_STOP } jpype-1.3.0/native/common/jp_inttype.cpp000066400000000000000000000220571405671516700203330ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "pyjp.h" #include "jp_array.h" #include "jp_primitive_accessor.h" #include "jp_inttype.h" JPIntType::JPIntType() : JPPrimitiveType("int") { } JPIntType::~JPIntType() { } JPPyObject JPIntType::convertToPythonObject(JPJavaFrame& frame, jvalue val, bool cast) { JPPyObject tmp = JPPyObject::call(PyLong_FromLong(field(val))); if (getHost() == NULL) return tmp; JPPyObject out = JPPyObject::call(convertLong(getHost(), (PyLongObject*) tmp.get())); PyJPValue_assignJavaSlot(frame, out.get(), JPValue(this, val)); return out; } JPValue JPIntType::getValueFromObject(const JPValue& obj) { JPContext *context = obj.getClass()->getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); jvalue v; jobject jo = obj.getValue().l; JPBoxedType* jb = (JPBoxedType*) frame.findClassForObject(jo); field(v) = (type_t) frame.CallIntMethodA(jo, jb->m_IntValueID, 0); return JPValue(this, v); } JPConversionLong intConversion; JPConversionLongNumber intNumberConversion; JPConversionLongWiden intWidenConversion; class JPConversionJInt : public JPConversionJavaValue { public: virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) override { JPValue *value = match.getJavaSlot(); if (value == NULL) return JPMatch::_none; match.type = JPMatch::_none; // Implied conversion from boxed to primitive (JLS 5.1.8) if (javaValueConversion->matches(cls, match) || unboxConversion->matches(cls, match)) return match.type; // Consider widening JPClass *cls2 = value->getClass(); if (cls2->isPrimitive()) { // https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.2 JPPrimitiveType *prim = (JPPrimitiveType*) cls2; switch (prim->getTypeCode()) { case 'C': case 'S': case 'B': match.conversion = &intWidenConversion; return match.type = JPMatch::_implicit; default: break; } } // Unboxing must be to the from the exact boxed type (JLS 5.1.8) return JPMatch::_implicit; //short cut further checks } virtual void getInfo(JPClass *cls, JPConversionInfo &info) override { JPContext *context = cls->getContext(); PyList_Append(info.exact, (PyObject*) context->_int->getHost()); PyList_Append(info.implicit, (PyObject*) context->_byte->getHost()); PyList_Append(info.implicit, (PyObject*) context->_char->getHost()); PyList_Append(info.implicit, (PyObject*) context->_short->getHost()); unboxConversion->getInfo(cls, info); } } jintConversion; JPMatch::Type JPIntType::findJavaConversion(JPMatch &match) { JP_TRACE_IN("JPIntType::findJavaConversion"); if (match.object == Py_None) return match.type = JPMatch::_none; if (jintConversion.matches(this, match) || intConversion.matches(this, match) || intNumberConversion.matches(this, match)) return match.type; return match.type = JPMatch::_none; JP_TRACE_OUT; } void JPIntType::getConversionInfo(JPConversionInfo &info) { JPJavaFrame frame = JPJavaFrame::outer(m_Context); jintConversion.getInfo(this, info); intConversion.getInfo(this, info); intNumberConversion.getInfo(this, info); PyList_Append(info.ret, (PyObject*) m_Context->_int->getHost()); } jarray JPIntType::newArrayOf(JPJavaFrame& frame, jsize sz) { return frame.NewIntArray(sz); } JPPyObject JPIntType::getStaticField(JPJavaFrame& frame, jclass c, jfieldID fid) { jvalue v; field(v) = frame.GetStaticIntField(c, fid); return convertToPythonObject(frame, v, false); } JPPyObject JPIntType::getField(JPJavaFrame& frame, jobject c, jfieldID fid) { jvalue v; field(v) = frame.GetIntField(c, fid); return convertToPythonObject(frame, v, false); } JPPyObject JPIntType::invokeStatic(JPJavaFrame& frame, jclass claz, jmethodID mth, jvalue* val) { jvalue v; { JPPyCallRelease call; field(v) = frame.CallStaticIntMethodA(claz, mth, val); } return convertToPythonObject(frame, v, false); } JPPyObject JPIntType::invoke(JPJavaFrame& frame, jobject obj, jclass clazz, jmethodID mth, jvalue* val) { jvalue v; { JPPyCallRelease call; if (clazz == NULL) field(v) = frame.CallIntMethodA(obj, mth, val); else field(v) = frame.CallNonvirtualIntMethodA(obj, clazz, mth, val); } return convertToPythonObject(frame, v, false); } void JPIntType::setStaticField(JPJavaFrame& frame, jclass c, jfieldID fid, PyObject* obj) { JPMatch match(&frame, obj); if (findJavaConversion(match) < JPMatch::_implicit) JP_RAISE(PyExc_TypeError, "Unable to convert to Java int"); type_t val = field(match.convert()); frame.SetStaticIntField(c, fid, val); } void JPIntType::setField(JPJavaFrame& frame, jobject c, jfieldID fid, PyObject* obj) { JPMatch match(&frame, obj); if (findJavaConversion(match) < JPMatch::_implicit) JP_RAISE(PyExc_TypeError, "Unable to convert to Java int"); type_t val = field(match.convert()); frame.SetIntField(c, fid, val); } void JPIntType::setArrayRange(JPJavaFrame& frame, jarray a, jsize start, jsize length, jsize step, PyObject* sequence) { JP_TRACE_IN("JPIntType::setArrayRange"); JPPrimitiveArrayAccessor accessor(frame, a, &JPJavaFrame::GetIntArrayElements, &JPJavaFrame::ReleaseIntArrayElements); type_t* val = accessor.get(); // First check if assigning sequence supports buffer API if (PyObject_CheckBuffer(sequence)) { JPPyBuffer buffer(sequence, PyBUF_FULL_RO); if (buffer.valid()) { Py_buffer& view = buffer.getView(); if (view.ndim != 1) JP_RAISE(PyExc_TypeError, "buffer dims incorrect"); Py_ssize_t vshape = view.shape[0]; Py_ssize_t vstep = view.strides[0]; if (vshape != length) JP_RAISE(PyExc_ValueError, "mismatched size"); char* memory = (char*) view.buf; if (view.suboffsets && view.suboffsets[0] >= 0) memory = *((char**) memory) + view.suboffsets[0]; jsize index = start; jconverter conv = getConverter(view.format, (int) view.itemsize, "i"); for (Py_ssize_t i = 0; i < length; ++i, index += step) { jvalue r = conv(memory); val[index] = r.i; memory += vstep; } accessor.commit(); return; } else { PyErr_Clear(); } } // Use sequence API JPPySequence seq = JPPySequence::use(sequence); jsize index = start; for (Py_ssize_t i = 0; i < length; ++i, index += step) { PyObject *item = seq[i].get(); if (!PyIndex_Check(item)) { PyErr_Format(PyExc_TypeError, "Unable to implicitly convert '%s' to int", Py_TYPE(item)->tp_name); JP_RAISE_PYTHON(); } jlong v = PyLong_AsLongLong(item); if (v == -1) JP_PY_CHECK(); val[index] = (type_t) assertRange(v); } accessor.commit(); JP_TRACE_OUT; } JPPyObject JPIntType::getArrayItem(JPJavaFrame& frame, jarray a, jsize ndx) { array_t array = (array_t) a; type_t val; frame.GetIntArrayRegion(array, ndx, 1, &val); jvalue v; field(v) = val; return convertToPythonObject(frame, v, false); } void JPIntType::setArrayItem(JPJavaFrame& frame, jarray a, jsize ndx, PyObject* obj) { JPMatch match(&frame, obj); if (findJavaConversion(match) < JPMatch::_implicit) JP_RAISE(PyExc_TypeError, "Unable to convert to Java int"); type_t val = field(match.convert()); frame.SetIntArrayRegion((array_t) a, ndx, 1, &val); } void JPIntType::getView(JPArrayView& view) { JPJavaFrame frame = JPJavaFrame::outer(view.getContext()); view.m_IsCopy = false; view.m_Memory = (void*) frame.GetIntArrayElements( (jintArray) view.m_Array->getJava(), &view.m_IsCopy); view.m_Buffer.format = "i"; view.m_Buffer.itemsize = sizeof (jint); } void JPIntType::releaseView(JPArrayView& view) { try { JPJavaFrame frame = JPJavaFrame::outer(view.getContext()); frame.ReleaseIntArrayElements((jintArray) view.m_Array->getJava(), (jint*) view.m_Memory, view.m_Buffer.readonly ? JNI_ABORT : 0); } catch (JPypeException&) { // This is called as part of the cleanup routine and exceptions // are not permitted } } const char* JPIntType::getBufferFormat() { return "i"; } ssize_t JPIntType::getItemSize() { return sizeof (jfloat); } void JPIntType::copyElements(JPJavaFrame &frame, jarray a, jsize start, jsize len, void* memory, int offset) { jint* b = (jint*) ((char*) memory + offset); frame.GetIntArrayRegion((jintArray) a, start, len, b); } static void pack(jint* d, jvalue v) { *d = v.i; } PyObject *JPIntType::newMultiArray(JPJavaFrame &frame, JPPyBuffer &buffer, int subs, int base, jobject dims) { JP_TRACE_IN("JPIntType::newMultiArray"); return convertMultiArray( frame, this, &pack, "i", buffer, subs, base, dims); JP_TRACE_OUT; } jpype-1.3.0/native/common/jp_javaframe.cpp000066400000000000000000001051241405671516700205700ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include #include "jpype.h" #include "jp_reference_queue.h" /*****************************************************************************/ // Local frames represent the JNIEnv for memory handling all java // resources should be created within them. // #if defined(JP_TRACING_ENABLE) || defined(JP_INSTRUMENTATION) static void jpype_frame_check(int popped) { if (popped) JP_RAISE(PyExc_SystemError, "Local reference outside of frame"); } #define JP_FRAME_CHECK() jpype_frame_check(m_Popped) #else #define JP_FRAME_CHECK() if (false) while (false) #endif JPJavaFrame::JPJavaFrame(JPContext* context, JNIEnv* p_env, int size, bool outer) : m_Context(context), m_Env(p_env), m_Popped(false), m_Outer(outer) { if (p_env == NULL) m_Env = context->getEnv(); // Create a memory management frame to live in m_Env->PushLocalFrame(size); JP_TRACE_JAVA("JavaFrame", (jobject) - 1); } JPJavaFrame::JPJavaFrame(const JPJavaFrame& frame) : m_Context(frame.m_Context), m_Env(frame.m_Env), m_Popped(false), m_Outer(false) { // Create a memory management frame to live in m_Env->PushLocalFrame(LOCAL_FRAME_DEFAULT); JP_TRACE_JAVA("JavaFrame (copy)", (jobject) - 1); } jobject JPJavaFrame::keep(jobject obj) { if (m_Outer) JP_RAISE(PyExc_SystemError, "Keep on outer frame"); JP_FRAME_CHECK(); m_Popped = true; JP_TRACE_JAVA("Keep", obj); JP_TRACE_JAVA("~JavaFrame (keep)", (jobject) - 2); obj = m_Env->PopLocalFrame(obj); JP_TRACE_JAVA("Return", obj); return obj; } JPJavaFrame::~JPJavaFrame() { // Check if we have already closed the frame. if (!m_Popped) { JP_TRACE_JAVA("~JavaFrame", (jobject) - 2); m_Env->PopLocalFrame(NULL); JP_FRAME_CHECK(); } // It is not safe to detach as we would loss all local references including // any we want to keep. } void JPJavaFrame::DeleteLocalRef(jobject obj) { JP_TRACE_JAVA("Delete local", obj); m_Env->DeleteLocalRef(obj); } void JPJavaFrame::DeleteGlobalRef(jobject obj) { JP_TRACE_JAVA("Delete global", obj); m_Env->DeleteGlobalRef(obj); } jweak JPJavaFrame::NewWeakGlobalRef(jobject obj) { JP_FRAME_CHECK(); JP_TRACE_JAVA("New weak", obj); jweak obj2 = m_Env->NewWeakGlobalRef(obj); JP_TRACE_JAVA("Weak", obj2); return obj2; } void JPJavaFrame::DeleteWeakGlobalRef(jweak obj) { JP_TRACE_JAVA("Delete weak", obj); return m_Env->DeleteWeakGlobalRef(obj); } jobject JPJavaFrame::NewLocalRef(jobject obj) { JP_FRAME_CHECK(); JP_TRACE_JAVA("New local", obj); obj = m_Env->NewLocalRef(obj); JP_TRACE_JAVA("Local", obj); return obj; } jobject JPJavaFrame::NewGlobalRef(jobject obj) { JP_TRACE_JAVA("New Global", obj); obj = m_Env->NewGlobalRef(obj); JP_TRACE_JAVA("Global", obj); return obj; } /*****************************************************************************/ // Exceptions bool JPJavaFrame::ExceptionCheck() { return (m_Env->ExceptionCheck() ? true : false); } void JPJavaFrame::ExceptionDescribe() { m_Env->ExceptionDescribe(); } void JPJavaFrame::ExceptionClear() { m_Env->ExceptionClear(); } jint JPJavaFrame::ThrowNew(jclass clazz, const char* msg) { return m_Env->ThrowNew(clazz, msg); } jint JPJavaFrame::Throw(jthrowable th) { return m_Env->Throw(th); } jthrowable JPJavaFrame::ExceptionOccurred() { JP_FRAME_CHECK(); jthrowable obj; obj = m_Env->ExceptionOccurred(); #ifdef JP_TRACING_ENABLE if (obj) { m_Env->ExceptionDescribe(); } #endif JP_TRACE_JAVA("Exception", obj); return obj; } /*****************************************************************************/ #ifdef JP_INSTRUMENTATION #define JAVA_RETURN(X,Y,Z) \ PyJPModuleFault_throw(compile_hash(Y)); \ X ret = Z; \ check(); \ return ret; #define JAVA_RETURN_OBJ(X,Y,Z) \ PyJPModuleFault_throw(compile_hash(Y)); \ X ret = Z; \ check(); \ return ret; #define JAVA_CHECK(Y,Z) \ PyJPModuleFault_throw(compile_hash(Y)); \ Z; \ check(); #else #define JAVA_RETURN(X,Y,Z) \ X ret = Z; \ JP_TRACE_JAVA(Y, 0); \ check(); \ return ret; #define JAVA_RETURN_OBJ(X,Y,Z) \ JP_FRAME_CHECK(); \ X ret = Z; \ JP_TRACE_JAVA(Y, ret); \ check(); \ return ret; #define JAVA_CHECK(Y,Z) \ Z; \ JP_TRACE_JAVA(Y, 0); \ check(); #endif void JPJavaFrame::check() { JP_FRAME_CHECK(); if (m_Env && m_Env->ExceptionCheck() == JNI_TRUE) { jthrowable th = m_Env->ExceptionOccurred(); JP_TRACE_JAVA("ExceptionOccurred", th); m_Env->ExceptionClear(); JP_TRACE_JAVA("ExceptionClear", 0); throw JPypeException(*this, th, JP_STACKINFO()); } } jobject JPJavaFrame::NewObjectA(jclass a0, jmethodID a1, jvalue* a2) { jobject res; JP_FRAME_CHECK(); // Allocate the object JAVA_CHECK("JPJavaFrame::JPJavaFrame::NewObjectA", res = m_Env->AllocObject(a0)); JAVA_CHECK("JPJavaFrame::NewObjectA::AllocObject", m_Env->CallVoidMethodA(res, a1, a2)); JP_TRACE_JAVA("NewObjectA", res); // Initialize the object return res; } jobject JPJavaFrame::NewDirectByteBuffer(void* address, jlong capacity) { JAVA_RETURN_OBJ(jobject, "JPJavaFrame::NewDirectByteBuffer", m_Env->NewDirectByteBuffer(address, capacity)); } /*****************************************************************************/ jbyte JPJavaFrame::GetStaticByteField(jclass clazz, jfieldID fid) { JAVA_RETURN(jbyte, "JPJavaFrame::GetStaticByteField", m_Env->GetStaticByteField(clazz, fid)); } jbyte JPJavaFrame::GetByteField(jobject clazz, jfieldID fid) { JAVA_RETURN(jbyte, "JPJavaFrame::GetByteField", m_Env->GetByteField(clazz, fid)); } void JPJavaFrame::SetStaticByteField(jclass clazz, jfieldID fid, jbyte val) { JAVA_CHECK("JPJavaFrame::SetStaticByteField", m_Env->SetStaticByteField(clazz, fid, val)); } void JPJavaFrame::SetByteField(jobject clazz, jfieldID fid, jbyte val) { JAVA_CHECK("JPJavaFrame::SetByteField", m_Env->SetByteField(clazz, fid, val)); } jbyte JPJavaFrame::CallStaticByteMethodA(jclass clazz, jmethodID mid, jvalue* val) { JAVA_RETURN(jbyte, "JPJavaFrame::CallStaticByteMethodA", m_Env->CallStaticByteMethodA(clazz, mid, val)); } jbyte JPJavaFrame::CallByteMethodA(jobject obj, jmethodID mid, jvalue* val) { JAVA_RETURN(jbyte, "JPJavaFrame::CallByteMethodA", m_Env->CallByteMethodA(obj, mid, val)); } jbyte JPJavaFrame::CallNonvirtualByteMethodA(jobject obj, jclass claz, jmethodID mid, jvalue* val) { JAVA_RETURN(jbyte, "JPJavaFrame::CallNonvirtualByteMethodA", m_Env->CallNonvirtualByteMethodA(obj, claz, mid, val)); } jshort JPJavaFrame::GetStaticShortField(jclass clazz, jfieldID fid) { JAVA_RETURN(jshort, "JPJavaFrame::GetStaticShortField", m_Env->GetStaticShortField(clazz, fid)); } jshort JPJavaFrame::GetShortField(jobject clazz, jfieldID fid) { JAVA_RETURN(jshort, "JPJavaFrame::GetShortField", m_Env->GetShortField(clazz, fid)); } void JPJavaFrame::SetStaticShortField(jclass clazz, jfieldID fid, jshort val) { JAVA_CHECK("JPJavaFrame::SetStaticShortField", m_Env->SetStaticShortField(clazz, fid, val)); } void JPJavaFrame::SetShortField(jobject clazz, jfieldID fid, jshort val) { JAVA_CHECK("JPJavaFrame::SetShortField", m_Env->SetShortField(clazz, fid, val)); } jshort JPJavaFrame::CallStaticShortMethodA(jclass clazz, jmethodID mid, jvalue* val) { JAVA_RETURN(jshort, "JPJavaFrame::CallStaticShortMethodA", m_Env->CallStaticShortMethodA(clazz, mid, val)); } jshort JPJavaFrame::CallShortMethodA(jobject obj, jmethodID mid, jvalue* val) { JAVA_RETURN(jshort, "JPJavaFrame::CallShortMethodA", m_Env->CallShortMethodA(obj, mid, val)); } jshort JPJavaFrame::CallNonvirtualShortMethodA(jobject obj, jclass claz, jmethodID mid, jvalue* val) { JAVA_RETURN(jshort, "JPJavaFrame::CallNonvirtualShortMethodA", m_Env->CallNonvirtualShortMethodA(obj, claz, mid, val)); } jint JPJavaFrame::GetStaticIntField(jclass clazz, jfieldID fid) { JAVA_RETURN(jint, "JPJavaFrame::GetStaticIntField", m_Env->GetStaticIntField(clazz, fid)); } jint JPJavaFrame::GetIntField(jobject clazz, jfieldID fid) { JAVA_RETURN(jint, "JPJavaFrame::GetIntField", m_Env->GetIntField(clazz, fid)); } void JPJavaFrame::SetStaticIntField(jclass clazz, jfieldID fid, jint val) { JAVA_CHECK("JPJavaFrame::SetStaticIntField", m_Env->SetStaticIntField(clazz, fid, val)); } void JPJavaFrame::SetIntField(jobject clazz, jfieldID fid, jint val) { JAVA_CHECK("JPJavaFrame::SetIntField", m_Env->SetIntField(clazz, fid, val)); } jint JPJavaFrame::CallStaticIntMethodA(jclass clazz, jmethodID mid, jvalue* val) { JAVA_RETURN(jint, "JPJavaFrame::CallStaticIntMethodA", m_Env->CallStaticIntMethodA(clazz, mid, val)); } jint JPJavaFrame::CallIntMethodA(jobject obj, jmethodID mid, jvalue* val) { JAVA_RETURN(jint, "JPJavaFrame::CallIntMethodA", m_Env->CallIntMethodA(obj, mid, val)); } jint JPJavaFrame::CallNonvirtualIntMethodA(jobject obj, jclass claz, jmethodID mid, jvalue* val) { JAVA_RETURN(jint, "JPJavaFrame::CallNonvirtualIntMethodA", m_Env->CallNonvirtualIntMethodA(obj, claz, mid, val)); } jlong JPJavaFrame::GetStaticLongField(jclass clazz, jfieldID fid) { JAVA_RETURN(jlong, "JPJavaFrame::GetStaticLongField", m_Env->GetStaticLongField(clazz, fid)); } jlong JPJavaFrame::GetLongField(jobject clazz, jfieldID fid) { JAVA_RETURN(jlong, "JPJavaFrame::GetLongField", m_Env->GetLongField(clazz, fid)); } void JPJavaFrame::SetStaticLongField(jclass clazz, jfieldID fid, jlong val) { JAVA_CHECK("JPJavaFrame::SetStaticLongField", m_Env->SetStaticLongField(clazz, fid, val)); } void JPJavaFrame::SetLongField(jobject clazz, jfieldID fid, jlong val) { JAVA_CHECK("JPJavaFrame::SetLongField", m_Env->SetLongField(clazz, fid, val)); } jlong JPJavaFrame::CallStaticLongMethodA(jclass clazz, jmethodID mid, jvalue* val) { JAVA_RETURN(jlong, "JPJavaFrame::CallStaticLongMethodA", m_Env->CallStaticLongMethodA(clazz, mid, val)); } jlong JPJavaFrame::CallLongMethodA(jobject obj, jmethodID mid, jvalue* val) { JAVA_RETURN(jlong, "JPJavaFrame::CallLongMethodA", m_Env->CallLongMethodA(obj, mid, val)); } jlong JPJavaFrame::CallNonvirtualLongMethodA(jobject obj, jclass claz, jmethodID mid, jvalue* val) { JAVA_RETURN(jlong, "JPJavaFrame::CallNonvirtualLongMethodA", m_Env->CallNonvirtualLongMethodA(obj, claz, mid, val)); } jfloat JPJavaFrame::GetStaticFloatField(jclass clazz, jfieldID fid) { JAVA_RETURN(jfloat, "JPJavaFrame::GetStaticFloatField", m_Env->GetStaticFloatField(clazz, fid)); } jfloat JPJavaFrame::GetFloatField(jobject clazz, jfieldID fid) { JAVA_RETURN(jfloat, "JPJavaFrame::GetFloatField", m_Env->GetFloatField(clazz, fid)); } void JPJavaFrame::SetStaticFloatField(jclass clazz, jfieldID fid, jfloat val) { JAVA_CHECK("JPJavaFrame::SetStaticFloatField", m_Env->SetStaticFloatField(clazz, fid, val)); } void JPJavaFrame::SetFloatField(jobject clazz, jfieldID fid, jfloat val) { JAVA_CHECK("JPJavaFrame::SetFloatField", m_Env->SetFloatField(clazz, fid, val)); } jfloat JPJavaFrame::CallStaticFloatMethodA(jclass clazz, jmethodID mid, jvalue* val) { JAVA_RETURN(jfloat, "JPJavaFrame::CallStaticFloatMethodA", m_Env->CallStaticFloatMethodA(clazz, mid, val)); } jfloat JPJavaFrame::CallFloatMethodA(jobject obj, jmethodID mid, jvalue* val) { JAVA_RETURN(jfloat, "JPJavaFrame::CallFloatMethodA", m_Env->CallFloatMethodA(obj, mid, val)); } jfloat JPJavaFrame::CallNonvirtualFloatMethodA(jobject obj, jclass claz, jmethodID mid, jvalue* val) { JAVA_RETURN(jfloat, "JPJavaFrame::CallNonvirtualFloatMethodA", m_Env->CallNonvirtualFloatMethodA(obj, claz, mid, val)); } jdouble JPJavaFrame::GetStaticDoubleField(jclass clazz, jfieldID fid) { JAVA_RETURN(jdouble, "JPJavaFrame::GetStaticDoubleField", m_Env->GetStaticDoubleField(clazz, fid)); } jdouble JPJavaFrame::GetDoubleField(jobject clazz, jfieldID fid) { JAVA_RETURN(jdouble, "JPJavaFrame::GetDoubleField", m_Env->GetDoubleField(clazz, fid)); } void JPJavaFrame::SetStaticDoubleField(jclass clazz, jfieldID fid, jdouble val) { JAVA_CHECK("JPJavaFrame::SetStaticDoubleField", m_Env->SetStaticDoubleField(clazz, fid, val)); } void JPJavaFrame::SetDoubleField(jobject clazz, jfieldID fid, jdouble val) { JAVA_CHECK("JPJavaFrame::SetDoubleField", m_Env->SetDoubleField(clazz, fid, val)); } jdouble JPJavaFrame::CallStaticDoubleMethodA(jclass clazz, jmethodID mid, jvalue* val) { JAVA_RETURN(jdouble, "JPJavaFrame::CallStaticDoubleMethodA", m_Env->CallStaticDoubleMethodA(clazz, mid, val)); } jdouble JPJavaFrame::CallDoubleMethodA(jobject obj, jmethodID mid, jvalue* val) { JAVA_RETURN(jdouble, "JPJavaFrame::CallDoubleMethodA", m_Env->CallDoubleMethodA(obj, mid, val)); } jdouble JPJavaFrame::CallNonvirtualDoubleMethodA(jobject obj, jclass claz, jmethodID mid, jvalue* val) { JAVA_RETURN(jdouble, "JPJavaFrame::CallNonvirtualDoubleMethodA", m_Env->CallNonvirtualDoubleMethodA(obj, claz, mid, val)); } jchar JPJavaFrame::GetStaticCharField(jclass clazz, jfieldID fid) { JAVA_RETURN(jchar, "JPJavaFrame::GetStaticCharField", m_Env->GetStaticCharField(clazz, fid)); } jchar JPJavaFrame::GetCharField(jobject clazz, jfieldID fid) { JAVA_RETURN(jchar, "JPJavaFrame::GetCharField", m_Env->GetCharField(clazz, fid)); } void JPJavaFrame::SetStaticCharField(jclass clazz, jfieldID fid, jchar val) { JAVA_CHECK("JPJavaFrame::SetStaticCharField", m_Env->SetStaticCharField(clazz, fid, val)); } void JPJavaFrame::SetCharField(jobject clazz, jfieldID fid, jchar val) { JAVA_CHECK("JPJavaFrame::SetCharField", m_Env->SetCharField(clazz, fid, val)); } jchar JPJavaFrame::CallStaticCharMethodA(jclass clazz, jmethodID mid, jvalue* val) { JAVA_RETURN(jchar, "JPJavaFrame::CallStaticCharMethodA", m_Env->CallStaticCharMethodA(clazz, mid, val)); } jchar JPJavaFrame::CallCharMethodA(jobject obj, jmethodID mid, jvalue* val) { JAVA_RETURN(jchar, "JPJavaFrame::CallCharMethodA", m_Env->CallCharMethodA(obj, mid, val)); } jchar JPJavaFrame::CallNonvirtualCharMethodA(jobject obj, jclass claz, jmethodID mid, jvalue* val) { JAVA_RETURN(jchar, "JPJavaFrame::CallNonvirtualCharMethodA", m_Env->CallNonvirtualCharMethodA(obj, claz, mid, val)); } jboolean JPJavaFrame::GetStaticBooleanField(jclass clazz, jfieldID fid) { JAVA_RETURN(jboolean, "JPJavaFrame::GetStaticBooleanField", m_Env->GetStaticBooleanField(clazz, fid)); } jboolean JPJavaFrame::GetBooleanField(jobject clazz, jfieldID fid) { JAVA_RETURN(jboolean, "JPJavaFrame::GetBooleanField", m_Env->GetBooleanField(clazz, fid)); } void JPJavaFrame::SetStaticBooleanField(jclass clazz, jfieldID fid, jboolean val) { JAVA_CHECK("JPJavaFrame::SetStaticBooleanField", m_Env->SetStaticBooleanField(clazz, fid, val)); } void JPJavaFrame::SetBooleanField(jobject clazz, jfieldID fid, jboolean val) { JAVA_CHECK("JPJavaFrame::SetBooleanField", m_Env->SetBooleanField(clazz, fid, val)); } jboolean JPJavaFrame::CallStaticBooleanMethodA(jclass clazz, jmethodID mid, jvalue* val) { JAVA_RETURN(jboolean, "JPJavaFrame::CallStaticBooleanMethodA", m_Env->CallStaticBooleanMethodA(clazz, mid, val)); } jboolean JPJavaFrame::CallBooleanMethodA(jobject obj, jmethodID mid, jvalue* val) { JAVA_RETURN(jboolean, "JPJavaFrame::CallBooleanMethodA", m_Env->CallBooleanMethodA(obj, mid, val)); } jboolean JPJavaFrame::CallNonvirtualBooleanMethodA(jobject obj, jclass claz, jmethodID mid, jvalue* val) { JAVA_RETURN(jboolean, "JPJavaFrame::CallNonvirtualBooleanMethodA", m_Env->CallNonvirtualBooleanMethodA(obj, claz, mid, val)); } jclass JPJavaFrame::GetObjectClass(jobject obj) { JAVA_RETURN_OBJ(jclass, "JPJavaFrame::GetObjectClass", m_Env->GetObjectClass(obj)); } jobject JPJavaFrame::GetStaticObjectField(jclass clazz, jfieldID fid) { JAVA_RETURN_OBJ(jobject, "JPJavaFrame::GetStaticObjectField", m_Env->GetStaticObjectField(clazz, fid)); } jobject JPJavaFrame::GetObjectField(jobject clazz, jfieldID fid) { JAVA_RETURN_OBJ(jobject, "JPJavaFrame::GetObjectField", m_Env->GetObjectField(clazz, fid)); } void JPJavaFrame::SetStaticObjectField(jclass clazz, jfieldID fid, jobject val) { JAVA_CHECK("JPJavaFrame::SetStaticObjectField", m_Env->SetStaticObjectField(clazz, fid, val)); } void JPJavaFrame::SetObjectField(jobject clazz, jfieldID fid, jobject val) { JAVA_CHECK("JPJavaFrame::SetObjectField", m_Env->SetObjectField(clazz, fid, val)); } jobject JPJavaFrame::CallStaticObjectMethodA(jclass clazz, jmethodID mid, jvalue* val) { JAVA_RETURN_OBJ(jobject, "JPJavaFrame::CallStaticObjectMethodA", m_Env->CallStaticObjectMethodA(clazz, mid, val)); } jobject JPJavaFrame::CallObjectMethodA(jobject obj, jmethodID mid, jvalue* val) { JAVA_RETURN_OBJ(jobject, "JPJavaFrame::CallObjectMethodA", m_Env->CallObjectMethodA(obj, mid, val)); } jobject JPJavaFrame::CallNonvirtualObjectMethodA(jobject obj, jclass claz, jmethodID mid, jvalue* val) { JAVA_RETURN_OBJ(jobject, "JPJavaFrame::CallNonvirtualObjectMethodA", m_Env->CallNonvirtualObjectMethodA(obj, claz, mid, val)); } jbyteArray JPJavaFrame::NewByteArray(jsize len) { JAVA_RETURN_OBJ(jbyteArray, "JPJavaFrame::NewByteArray", m_Env->NewByteArray(len)); } void JPJavaFrame::SetByteArrayRegion(jbyteArray array, jsize start, jsize len, jbyte* vals) { JAVA_CHECK("JPJavaFrame::SetByteArrayRegion", m_Env->SetByteArrayRegion(array, start, len, vals)); } void JPJavaFrame::GetByteArrayRegion(jbyteArray array, jsize start, jsize len, jbyte* vals) { JAVA_CHECK("JPJavaFrame::GetByteArrayRegion", m_Env->GetByteArrayRegion(array, start, len, vals)); } jbyte* JPJavaFrame::GetByteArrayElements(jbyteArray array, jboolean* isCopy) { JAVA_RETURN(jbyte*, "JPJavaFrame::GetByteArrayElements", m_Env->GetByteArrayElements(array, isCopy)); } void JPJavaFrame::ReleaseByteArrayElements(jbyteArray array, jbyte* v, jint mode) { JAVA_CHECK("JPJavaFrame::ReleaseByteArrayElements", m_Env->ReleaseByteArrayElements(array, v, mode)); } jshortArray JPJavaFrame::NewShortArray(jsize len) { JAVA_RETURN_OBJ(jshortArray, "JPJavaFrame::NewShortArray", m_Env->NewShortArray(len)); } void JPJavaFrame::SetShortArrayRegion(jshortArray array, jsize start, jsize len, jshort* vals) { JAVA_CHECK("JPJavaFrame::SetShortArrayRegion", m_Env->SetShortArrayRegion(array, start, len, vals)); } void JPJavaFrame::GetShortArrayRegion(jshortArray array, jsize start, jsize len, jshort* vals) { JAVA_CHECK("JPJavaFrame::GetShortArrayRegion", m_Env->GetShortArrayRegion(array, start, len, vals)); } jshort* JPJavaFrame::GetShortArrayElements(jshortArray array, jboolean* isCopy) { JAVA_RETURN(jshort*, "JPJavaFrame::GetShortArrayElements", m_Env->GetShortArrayElements(array, isCopy)); } void JPJavaFrame::ReleaseShortArrayElements(jshortArray array, jshort* v, jint mode) { JAVA_CHECK("JPJavaFrame::ReleaseShortArrayElements", m_Env->ReleaseShortArrayElements(array, v, mode)); } jintArray JPJavaFrame::NewIntArray(jsize len) { JAVA_RETURN_OBJ(jintArray, "JPJavaFrame::NewIntArray", m_Env->NewIntArray(len)); } void JPJavaFrame::SetIntArrayRegion(jintArray array, jsize start, jsize len, jint* vals) { JAVA_CHECK("JPJavaFrame::SetIntArrayRegion", m_Env->SetIntArrayRegion(array, start, len, vals)); } void JPJavaFrame::GetIntArrayRegion(jintArray array, jsize start, jsize len, jint* vals) { JAVA_CHECK("JPJavaFrame::GetIntArrayRegion", m_Env->GetIntArrayRegion(array, start, len, vals)); } jint* JPJavaFrame::GetIntArrayElements(jintArray array, jboolean* isCopy) { JAVA_RETURN(jint*, "JPJavaFrame::GetIntArrayElements", m_Env->GetIntArrayElements(array, isCopy)); } void JPJavaFrame::ReleaseIntArrayElements(jintArray array, jint* v, jint mode) { JAVA_CHECK("JPJavaFrame::ReleaseIntArrayElements", m_Env->ReleaseIntArrayElements(array, v, mode)); } jlongArray JPJavaFrame::NewLongArray(jsize len) { JAVA_RETURN_OBJ(jlongArray, "JPJavaFrame::NewLongArray", m_Env->NewLongArray(len)); } void JPJavaFrame::SetLongArrayRegion(jlongArray array, jsize start, jsize len, jlong* vals) { JAVA_CHECK("JPJavaFrame::SetLongArrayRegion", m_Env->SetLongArrayRegion(array, start, len, vals)); } void JPJavaFrame::GetLongArrayRegion(jlongArray array, jsize start, jsize len, jlong* vals) { JAVA_CHECK("JPJavaFrame::GetLongArrayRegion", m_Env->GetLongArrayRegion(array, start, len, vals)); } jlong* JPJavaFrame::GetLongArrayElements(jlongArray array, jboolean* isCopy) { JAVA_RETURN(jlong*, "JPJavaFrame::GetLongArrayElements", m_Env->GetLongArrayElements(array, isCopy)); } void JPJavaFrame::ReleaseLongArrayElements(jlongArray array, jlong* v, jint mode) { JAVA_CHECK("JPJavaFrame::ReleaseLongArrayElements", m_Env->ReleaseLongArrayElements(array, v, mode)); } jfloatArray JPJavaFrame::NewFloatArray(jsize len) { JAVA_RETURN_OBJ(jfloatArray, "JPJavaFrame::NewFloatArray", m_Env->NewFloatArray(len)); } void JPJavaFrame::SetFloatArrayRegion(jfloatArray array, jsize start, jsize len, jfloat* vals) { JAVA_CHECK("JPJavaFrame::SetFloatArrayRegion", m_Env->SetFloatArrayRegion(array, start, len, vals)); } void JPJavaFrame::GetFloatArrayRegion(jfloatArray array, jsize start, jsize len, jfloat* vals) { JAVA_CHECK("JPJavaFrame::GetFloatArrayRegion", m_Env->GetFloatArrayRegion(array, start, len, vals)); } jfloat* JPJavaFrame::GetFloatArrayElements(jfloatArray array, jboolean* isCopy) { JAVA_RETURN(jfloat*, "JPJavaFrame::GetFloatArrayElements", m_Env->GetFloatArrayElements(array, isCopy)); } void JPJavaFrame::ReleaseFloatArrayElements(jfloatArray array, jfloat* v, jint mode) { JAVA_CHECK("JPJavaFrame::ReleaseFloatArrayElements", m_Env->ReleaseFloatArrayElements(array, v, mode)); } jdoubleArray JPJavaFrame::NewDoubleArray(jsize len) { JAVA_RETURN_OBJ(jdoubleArray, "JPJavaFrame::NewDoubleArray", m_Env->NewDoubleArray(len)); } void JPJavaFrame::SetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len, jdouble* vals) { JAVA_CHECK("JPJavaFrame::SetDoubleArrayRegion", m_Env->SetDoubleArrayRegion(array, start, len, vals)); } void JPJavaFrame::GetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len, jdouble* vals) { JAVA_CHECK("JPJavaFrame::GetDoubleArrayRegion", m_Env->GetDoubleArrayRegion(array, start, len, vals)); } jdouble* JPJavaFrame::GetDoubleArrayElements(jdoubleArray array, jboolean* isCopy) { JAVA_RETURN(jdouble*, "JPJavaFrame::GetDoubleArrayElements", m_Env->GetDoubleArrayElements(array, isCopy)); } void JPJavaFrame::ReleaseDoubleArrayElements(jdoubleArray array, jdouble* v, jint mode) { JAVA_CHECK("JPJavaFrame::ReleaseDoubleArrayElements", m_Env->ReleaseDoubleArrayElements(array, v, mode)); } jcharArray JPJavaFrame::NewCharArray(jsize len) { JAVA_RETURN_OBJ(jcharArray, "JPJavaFrame::NewCharArray", m_Env->NewCharArray(len)); } void JPJavaFrame::SetCharArrayRegion(jcharArray array, jsize start, jsize len, jchar* vals) { JAVA_CHECK("JPJavaFrame::SetCharArrayRegion", m_Env->SetCharArrayRegion(array, start, len, vals)); } void JPJavaFrame::GetCharArrayRegion(jcharArray array, jsize start, jsize len, jchar* vals) { JAVA_CHECK("JPJavaFrame::GetCharArrayRegion", m_Env->GetCharArrayRegion(array, start, len, vals)); } jchar* JPJavaFrame::GetCharArrayElements(jcharArray array, jboolean* isCopy) { JAVA_RETURN(jchar*, "JPJavaFrame::GetCharArrayElements", m_Env->GetCharArrayElements(array, isCopy)); } void JPJavaFrame::ReleaseCharArrayElements(jcharArray array, jchar* v, jint mode) { JAVA_CHECK("JPJavaFrame::ReleaseCharArrayElements", m_Env->ReleaseCharArrayElements(array, v, mode)); } jbooleanArray JPJavaFrame::NewBooleanArray(jsize len) { JAVA_RETURN_OBJ(jbooleanArray, "JPJavaFrame::NewBooleanArray", m_Env->NewBooleanArray(len)); } void JPJavaFrame::SetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len, jboolean* vals) { JAVA_CHECK("JPJavaFrame::SetBooleanArrayRegion", m_Env->SetBooleanArrayRegion(array, start, len, vals)); } void JPJavaFrame::GetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len, jboolean* vals) { JAVA_CHECK("JPJavaFrame::GetBooleanArrayRegion", m_Env->GetBooleanArrayRegion(array, start, len, vals)); } jboolean* JPJavaFrame::GetBooleanArrayElements(jbooleanArray array, jboolean* isCopy) { JAVA_RETURN(jboolean*, "JPJavaFrame::GetBooleanArrayElements", m_Env->GetBooleanArrayElements(array, isCopy)); } void JPJavaFrame::ReleaseBooleanArrayElements(jbooleanArray array, jboolean* v, jint mode) { JAVA_CHECK("JPJavaFrame::ReleaseBooleanArrayElements", m_Env->ReleaseBooleanArrayElements(array, v, mode)); } int JPJavaFrame::MonitorEnter(jobject a0) { JAVA_RETURN(int, "JPJavaFrame::MonitorEnter", m_Env->MonitorEnter(a0)); } int JPJavaFrame::MonitorExit(jobject a0) { JAVA_RETURN(int, "JPJavaFrame::MonitorExit", m_Env->MonitorExit(a0)); } jmethodID JPJavaFrame::FromReflectedMethod(jobject a0) { JAVA_RETURN(jmethodID, "JPJavaFrame::FromReflectedMethod", m_Env->FromReflectedMethod(a0)); } jfieldID JPJavaFrame::FromReflectedField(jobject a0) { JAVA_RETURN(jfieldID, "JPJavaFrame::FromReflectedField", m_Env->FromReflectedField(a0)); } jclass JPJavaFrame::FindClass(const string& a0) { JAVA_RETURN(jclass, "JPJavaFrame::FindClass", m_Env->FindClass(a0.c_str())); } jobjectArray JPJavaFrame::NewObjectArray(jsize a0, jclass elementClass, jobject initialElement) { JAVA_RETURN(jobjectArray, "JPJavaFrame::NewObjectArray", m_Env->NewObjectArray(a0, elementClass, initialElement)); } void JPJavaFrame::SetObjectArrayElement(jobjectArray a0, jsize a1, jobject a2) { JAVA_CHECK("JPJavaFrame::SetObjectArrayElement", m_Env->SetObjectArrayElement(a0, a1, a2)); } void JPJavaFrame::CallStaticVoidMethodA(jclass a0, jmethodID a1, jvalue* a2) { JAVA_CHECK("JPJavaFrame::CallStaticVoidMethodA", m_Env->CallStaticVoidMethodA(a0, a1, a2)); } void JPJavaFrame::CallVoidMethodA(jobject a0, jmethodID a1, jvalue* a2) { JAVA_CHECK("JPJavaFrame::CallVoidMethodA", m_Env->CallVoidMethodA(a0, a1, a2)); } void JPJavaFrame::CallNonvirtualVoidMethodA(jobject a0, jclass a1, jmethodID a2, jvalue* a3) { JAVA_CHECK("JPJavaFrame::CallVoidMethodA", m_Env->CallNonvirtualVoidMethodA(a0, a1, a2, a3)); } jboolean JPJavaFrame::IsInstanceOf(jobject a0, jclass a1) { JAVA_RETURN(jboolean, "JPJavaFrame::IsInstanceOf", m_Env->IsInstanceOf(a0, a1)); } jboolean JPJavaFrame::IsAssignableFrom(jclass a0, jclass a1) { JAVA_RETURN(jboolean, "JPJavaFrame::IsAssignableFrom", m_Env->IsAssignableFrom(a0, a1)); } jstring JPJavaFrame::NewStringUTF(const char* a0) { JAVA_RETURN_OBJ(jstring, "JPJavaFrame::NewString", m_Env->NewStringUTF(a0)); } const char* JPJavaFrame::GetStringUTFChars(jstring a0, jboolean* a1) { JAVA_RETURN(const char*, "JPJavaFrame::GetStringUTFChars", m_Env->GetStringUTFChars(a0, a1)); } void JPJavaFrame::ReleaseStringUTFChars(jstring a0, const char* a1) { JAVA_CHECK("JPJavaFrame::ReleaseStringUTFChars", m_Env->ReleaseStringUTFChars(a0, a1)); } jsize JPJavaFrame::GetArrayLength(jarray a0) { JAVA_RETURN(jsize, "JPJavaFrame::GetArrayLength", m_Env->GetArrayLength(a0)); } jobject JPJavaFrame::GetObjectArrayElement(jobjectArray a0, jsize a1) { JAVA_RETURN_OBJ(jobject, "JPJavaFrame::GetObjectArrayElement", m_Env->GetObjectArrayElement(a0, a1)); } jmethodID JPJavaFrame::GetMethodID(jclass a0, const char* a1, const char* a2) { JAVA_RETURN(jmethodID, "JPJavaFrame::GetMethodID", m_Env->GetMethodID(a0, a1, a2)); } jmethodID JPJavaFrame::GetStaticMethodID(jclass a0, const char* a1, const char* a2) { JAVA_RETURN(jmethodID, "JPJavaFrame::GetStaticMethodID", m_Env->GetStaticMethodID(a0, a1, a2)); } jfieldID JPJavaFrame::GetFieldID(jclass a0, const char* a1, const char* a2) { JAVA_RETURN(jfieldID, "JPJavaFrame::GetFieldID", m_Env->GetFieldID(a0, a1, a2)); } jfieldID JPJavaFrame::GetStaticFieldID(jclass a0, const char* a1, const char* a2) { JAVA_RETURN(jfieldID, "JPJavaFrame::GetStaticFieldID", m_Env->GetStaticFieldID(a0, a1, a2)); } jsize JPJavaFrame::GetStringUTFLength(jstring a0) { JAVA_RETURN(jsize, "JPJavaFrame::GetStringUTFLength", m_Env->GetStringUTFLength(a0)); } jclass JPJavaFrame::DefineClass(const char* a0, jobject a1, const jbyte* a2, jsize a3) { JAVA_RETURN(jclass, "JPJavaFrame::DefineClass", m_Env->DefineClass(a0, a1, a2, a3)); } jint JPJavaFrame::RegisterNatives(jclass a0, const JNINativeMethod* a1, jint a2) { JAVA_RETURN(jint, "JPJavaFrame::RegisterNatives", m_Env->RegisterNatives(a0, a1, a2)); } void* JPJavaFrame::GetDirectBufferAddress(jobject obj) { JAVA_RETURN(void*, "JPJavaFrame::GetDirectBufferAddress", m_Env->GetDirectBufferAddress(obj)); } jlong JPJavaFrame::GetDirectBufferCapacity(jobject obj) { JAVA_RETURN(jlong, "JPJavaFrame::GetDirectBufferAddress", m_Env->GetDirectBufferCapacity(obj)); } jboolean JPJavaFrame::isBufferReadOnly(jobject obj) { return CallBooleanMethodA(obj, m_Context->m_Buffer_IsReadOnlyID, 0); } jboolean JPJavaFrame::orderBuffer(jobject obj) { jvalue arg; arg.l = obj; return CallBooleanMethodA(m_Context->m_JavaContext.get(), m_Context->m_Context_OrderID, &arg); } // GCOVR_EXCL_START // This is used when debugging reference counting problems. jclass JPJavaFrame::getClass(jobject obj) { return (jclass) CallObjectMethodA(obj, m_Context->m_Object_GetClassID, 0); } // GCOVR_EXCL_STOP class JPStringAccessor { JPJavaFrame& frame_; jboolean isCopy; public: const char* cstr; int length; jstring jstr_; JPStringAccessor(JPJavaFrame& frame, jstring jstr) : frame_(frame), jstr_(jstr) { cstr = frame_.GetStringUTFChars(jstr, &isCopy); length = frame_.GetStringUTFLength(jstr); } ~JPStringAccessor() { try { frame_.ReleaseStringUTFChars(jstr_, cstr); } catch (JPypeException&) { // Error during release must be eaten. // If Java does not accept a release of the buffer it // is Java's issue, not ours. } } } ; string JPJavaFrame::toString(jobject o) { jstring str = (jstring) CallObjectMethodA(o, m_Context->m_Object_ToStringID, 0); return toStringUTF8(str); } string JPJavaFrame::toStringUTF8(jstring str) { JPStringAccessor contents(*this, str); #ifdef ANDROID return string(contents.cstr, contents.length); #else return transcribe(contents.cstr, contents.length, JPEncodingJavaUTF8(), JPEncodingUTF8()); #endif } jstring JPJavaFrame::fromStringUTF8(const string& str) { #ifdef ANDROID return (jstring) NewStringUTF(str.c_str()); #else string mstr = transcribe(str.c_str(), str.size(), JPEncodingUTF8(), JPEncodingJavaUTF8()); return (jstring) NewStringUTF(mstr.c_str()); #endif } jobject JPJavaFrame::toCharArray(jstring jstr) { return CallObjectMethodA(jstr, m_Context->m_String_ToCharArrayID, 0); } bool JPJavaFrame::equals(jobject o1, jobject o2 ) { jvalue args; args.l = o2; return CallBooleanMethodA(o1, m_Context->m_Object_EqualsID, &args) != 0; } jint JPJavaFrame::hashCode(jobject o) { return CallIntMethodA(o, m_Context->m_Object_HashCodeID, 0); } jobject JPJavaFrame::collectRectangular(jarray obj) { if (m_Context->m_Context_collectRectangularID == 0) return 0; jvalue v; v.l = (jobject) obj; JAVA_RETURN(jobject, "JPJavaFrame::collectRectangular", CallObjectMethodA( m_Context->m_JavaContext.get(), m_Context->m_Context_collectRectangularID, &v)); } jobject JPJavaFrame::assemble(jobject dims, jobject parts) { if (m_Context->m_Context_collectRectangularID == 0) return 0; jvalue v[2]; v[0].l = (jobject) dims; v[1].l = (jobject) parts; JAVA_RETURN(jobject, "JPJavaFrame::assemble", CallObjectMethodA( m_Context->m_JavaContext.get(), m_Context->m_Context_assembleID, v)); } jobject JPJavaFrame::newArrayInstance(jclass c, jintArray dims) { jvalue v[2]; v[0].l = (jobject) c; v[1].l = (jobject) dims; JAVA_RETURN(jobject, "JPJavaFrame::newArrayInstance", CallStaticObjectMethodA( m_Context->m_Array.get(), m_Context->m_Array_NewInstanceID, v)); } jobject JPJavaFrame::callMethod(jobject method, jobject obj, jobject args) { JP_TRACE_IN("JPJavaFrame::callMethod"); if (m_Context->m_CallMethodID == 0) return NULL; JPJavaFrame frame(*this); jvalue v[3]; v[0].l = method; v[1].l = obj; v[2].l = args; return frame.keep(frame.CallObjectMethodA(m_Context->m_JavaContext.get(), m_Context->m_CallMethodID, v)); JP_TRACE_OUT; } string JPJavaFrame::getFunctional(jclass c) { jvalue v; v.l = (jobject) c; return toStringUTF8((jstring) CallObjectMethodA( m_Context->m_JavaContext.get(), m_Context->m_Context_GetFunctionalID, &v)); } JPClass *JPJavaFrame::findClass(jclass obj) { return m_Context->getTypeManager()->findClass(obj); } JPClass *JPJavaFrame::findClassByName(const string& name) { return m_Context->getTypeManager()->findClassByName(name); } JPClass *JPJavaFrame::findClassForObject(jobject obj) { return m_Context->getTypeManager()->findClassForObject(obj); } jint JPJavaFrame::compareTo(jobject obj, jobject obj2) { jvalue v; v.l = obj2; return CallIntMethodA(obj, m_Context->m_CompareToID, &v); } jthrowable JPJavaFrame::getCause(jthrowable th) { return (jthrowable) CallObjectMethodA((jobject) th, m_Context->m_Throwable_GetCauseID, NULL); } jstring JPJavaFrame::getMessage(jthrowable th) { return (jstring) CallObjectMethodA((jobject) th, m_Context->m_Throwable_GetMessageID, NULL); } jboolean JPJavaFrame::isPackage(const string& str) { jvalue v; v.l = fromStringUTF8(str); JAVA_RETURN(jboolean, "JPJavaFrame::isPackage", CallBooleanMethodA(m_Context->m_JavaContext.get(), m_Context->m_Context_IsPackageID, &v)); } jobject JPJavaFrame::getPackage(const string& str) { jvalue v; v.l = fromStringUTF8(str); JAVA_RETURN(jobject, "JPJavaFrame::getPackage", CallObjectMethodA(m_Context->m_JavaContext.get(), m_Context->m_Context_GetPackageID, &v)); } jobject JPJavaFrame::getPackageObject(jobject pkg, const string& str) { jvalue v; v.l = fromStringUTF8(str); JAVA_RETURN(jobject, "JPJavaFrame::getPackageObject", CallObjectMethodA(pkg, m_Context->m_Package_GetObjectID, &v)); } jarray JPJavaFrame::getPackageContents(jobject pkg) { jvalue v; JAVA_RETURN(jarray, "JPJavaFrame::getPackageContents", (jarray) CallObjectMethodA(pkg, m_Context->m_Package_GetContentsID, &v)); } void JPJavaFrame::newWrapper(JPClass* cls) { JPPyCallRelease call; jvalue jv; jv.j = (jlong) cls; CallVoidMethodA(m_Context->getJavaContext(), m_Context->m_Context_NewWrapperID, &jv); } void JPJavaFrame::registerRef(jobject obj, PyObject* hostRef) { JPReferenceQueue::registerRef(*this, obj, hostRef); } void JPJavaFrame::registerRef(jobject obj, void* ref, JCleanupHook cleanup) { JPReferenceQueue::registerRef(*this, obj, ref, cleanup); } void JPJavaFrame::clearInterrupt(bool throws) { JPPyCallRelease call; jvalue jv; jv.z = throws; CallVoidMethodA(m_Context->m_ContextClass.get(), m_Context->m_Context_ClearInterruptID, &jv); } jpype-1.3.0/native/common/jp_longtype.cpp000066400000000000000000000221321405671516700204720ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "pyjp.h" #include "jp_array.h" #include "jp_primitive_accessor.h" #include "jp_longtype.h" JPLongType::JPLongType() : JPPrimitiveType("long") { } JPLongType::~JPLongType() { } JPPyObject JPLongType::convertToPythonObject(JPJavaFrame& frame, jvalue val, bool cast) { JPPyObject tmp = JPPyObject::call(PyLong_FromLongLong(field(val))); JPPyObject out = JPPyObject::call(convertLong(getHost(), (PyLongObject*) tmp.get())); PyJPValue_assignJavaSlot(frame, out.get(), JPValue(this, val)); return out; } JPValue JPLongType::getValueFromObject(const JPValue& obj) { JPContext *context = obj.getClass()->getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); jvalue v; jobject jo = obj.getValue().l; JPBoxedType* jb = (JPBoxedType*) frame.findClassForObject(jo); field(v) = (type_t) frame.CallLongMethodA(jo, jb->m_LongValueID, 0); return JPValue(this, v); } JPConversionLong longConversion; JPConversionLongNumber longNumberConversion; JPConversionLongWiden longWidenConversion; class JPConversionJLong : public JPConversionJavaValue { public: virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) { JPValue* value = match.getJavaSlot(); if (value == NULL) return match.type = JPMatch::_none; // Implied conversion from boxed to primitive (JLS 5.1.8) if (javaValueConversion->matches(cls, match) || unboxConversion->matches(cls, match)) return match.type; // Consider widening JPClass *cls2 = value->getClass(); if (cls2->isPrimitive()) { // https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.2 JPPrimitiveType *prim = (JPPrimitiveType*) cls2; switch (prim->getTypeCode()) { case 'I': case 'C': case 'S': case 'B': match.conversion = &longWidenConversion; return match.type = JPMatch::_implicit; default: break; } } // Unboxing must be to the from the exact boxed type (JLS 5.1.8) match.type = JPMatch::_none; return JPMatch::_implicit; } void getInfo(JPClass *cls, JPConversionInfo &info) { JPContext *context = cls->getContext(); PyList_Append(info.exact, (PyObject*) context->_long->getHost()); PyList_Append(info.implicit, (PyObject*) context->_byte->getHost()); PyList_Append(info.implicit, (PyObject*) context->_char->getHost()); PyList_Append(info.implicit, (PyObject*) context->_short->getHost()); PyList_Append(info.implicit, (PyObject*) context->_int->getHost()); unboxConversion->getInfo(cls, info); } } jlongConversion; JPMatch::Type JPLongType::findJavaConversion(JPMatch &match) { JP_TRACE_IN("JPLongType::findJavaConversion"); if (match.object == Py_None) return match.type = JPMatch::_none; if (jlongConversion.matches(this, match) || longConversion.matches(this, match) || longNumberConversion.matches(this, match)) return match.type; return match.type = JPMatch::_none; JP_TRACE_OUT; } void JPLongType::getConversionInfo(JPConversionInfo &info) { JPJavaFrame frame = JPJavaFrame::outer(m_Context); jlongConversion.getInfo(this, info); longConversion.getInfo(this, info); longNumberConversion.getInfo(this, info); PyList_Append(info.ret, (PyObject*) m_Context->_long->getHost()); } jarray JPLongType::newArrayOf(JPJavaFrame& frame, jsize sz) { return frame.NewLongArray(sz); } JPPyObject JPLongType::getStaticField(JPJavaFrame& frame, jclass c, jfieldID fid) { jvalue v; field(v) = frame.GetStaticLongField(c, fid); return convertToPythonObject(frame, v, false); } JPPyObject JPLongType::getField(JPJavaFrame& frame, jobject c, jfieldID fid) { jvalue v; field(v) = frame.GetLongField(c, fid); return convertToPythonObject(frame, v, false); } JPPyObject JPLongType::invokeStatic(JPJavaFrame& frame, jclass claz, jmethodID mth, jvalue* val) { jvalue v; { JPPyCallRelease call; field(v) = frame.CallStaticLongMethodA(claz, mth, val); } return convertToPythonObject(frame, v, false); } JPPyObject JPLongType::invoke(JPJavaFrame& frame, jobject obj, jclass clazz, jmethodID mth, jvalue* val) { jvalue v; { JPPyCallRelease call; if (clazz == NULL) field(v) = frame.CallLongMethodA(obj, mth, val); else field(v) = frame.CallNonvirtualLongMethodA(obj, clazz, mth, val); } return convertToPythonObject(frame, v, false); } void JPLongType::setStaticField(JPJavaFrame& frame, jclass c, jfieldID fid, PyObject* obj) { JPMatch match(&frame, obj); if (findJavaConversion(match) < JPMatch::_implicit) JP_RAISE(PyExc_TypeError, "Unable to convert to Java int"); type_t val = field(match.convert()); frame.SetStaticLongField(c, fid, val); } void JPLongType::setField(JPJavaFrame& frame, jobject c, jfieldID fid, PyObject* obj) { JPMatch match(&frame, obj); if (findJavaConversion(match) < JPMatch::_implicit) JP_RAISE(PyExc_TypeError, "Unable to convert to Java int"); type_t val = field(match.convert()); frame.SetLongField(c, fid, val); } void JPLongType::setArrayRange(JPJavaFrame& frame, jarray a, jsize start, jsize length, jsize step, PyObject* sequence) { JP_TRACE_IN("JPLongType::setArrayRange"); JPPrimitiveArrayAccessor accessor(frame, a, &JPJavaFrame::GetLongArrayElements, &JPJavaFrame::ReleaseLongArrayElements); type_t* val = accessor.get(); // First check if assigning sequence supports buffer API if (PyObject_CheckBuffer(sequence)) { JPPyBuffer buffer(sequence, PyBUF_FULL_RO); if (buffer.valid()) { Py_buffer& view = buffer.getView(); if (view.ndim != 1) JP_RAISE(PyExc_TypeError, "buffer dims incorrect"); Py_ssize_t vshape = view.shape[0]; Py_ssize_t vstep = view.strides[0]; if (vshape != length) JP_RAISE(PyExc_ValueError, "mismatched size"); char* memory = (char*) view.buf; if (view.suboffsets && view.suboffsets[0] >= 0) memory = *((char**) memory) + view.suboffsets[0]; jsize index = start; jconverter conv = getConverter(view.format, (int) view.itemsize, "j"); for (Py_ssize_t i = 0; i < length; ++i, index += step) { jvalue r = conv(memory); val[index] = r.j; memory += vstep; } accessor.commit(); return; } else { PyErr_Clear(); } } // Use sequence API JPPySequence seq = JPPySequence::use(sequence); jsize index = start; for (Py_ssize_t i = 0; i < length; ++i, index += step) { PyObject *item = seq[i].get(); if (!PyIndex_Check(item)) { PyErr_Format(PyExc_TypeError, "Unable to implicitly convert '%s' to long", Py_TYPE(item)->tp_name); JP_RAISE_PYTHON(); } jlong v = PyLong_AsLongLong(item); if (v == -1) JP_PY_CHECK() val[index] = (type_t) v; } accessor.commit(); JP_TRACE_OUT; } JPPyObject JPLongType::getArrayItem(JPJavaFrame& frame, jarray a, jsize ndx) { array_t array = (array_t) a; type_t val; frame.GetLongArrayRegion(array, ndx, 1, &val); jvalue v; field(v) = val; return convertToPythonObject(frame, v, false); } void JPLongType::setArrayItem(JPJavaFrame& frame, jarray a, jsize ndx, PyObject* obj) { JPMatch match(&frame, obj); if (findJavaConversion(match) < JPMatch::_implicit) JP_RAISE(PyExc_TypeError, "Unable to convert to Java int"); type_t val = field(match.convert()); frame.SetLongArrayRegion((array_t) a, ndx, 1, &val); } void JPLongType::getView(JPArrayView& view) { JPJavaFrame frame = JPJavaFrame::outer(view.getContext()); view.m_Memory = (void*) frame.GetLongArrayElements( (jlongArray) view.m_Array->getJava(), &view.m_IsCopy); view.m_Buffer.format = "q"; view.m_Buffer.itemsize = sizeof (jlong); } void JPLongType::releaseView(JPArrayView& view) { try { JPJavaFrame frame = JPJavaFrame::outer(view.getContext()); frame.ReleaseLongArrayElements((jlongArray) view.m_Array->getJava(), (jlong*) view.m_Memory, view.m_Buffer.readonly ? JNI_ABORT : 0); } catch (JPypeException&) { // This is called as part of the cleanup routine and exceptions // are not permitted } } const char* JPLongType::getBufferFormat() { return "q"; } ssize_t JPLongType::getItemSize() { return sizeof (jlong); } void JPLongType::copyElements(JPJavaFrame &frame, jarray a, jsize start, jsize len, void* memory, int offset) { jlong* b = (jlong*) ((char*) memory + offset); frame.GetLongArrayRegion((jlongArray) a, start, len, b); } static void pack(jlong* d, jvalue v) { *d = v.j; } PyObject *JPLongType::newMultiArray(JPJavaFrame &frame, JPPyBuffer &buffer, int subs, int base, jobject dims) { JP_TRACE_IN("JPLongType::newMultiArray"); return convertMultiArray( frame, this, &pack, "j", buffer, subs, base, dims); JP_TRACE_OUT; } jpype-1.3.0/native/common/jp_method.cpp000066400000000000000000000242331405671516700201150ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "jp_arrayclass.h" #include "jp_boxedtype.h" #include "jp_method.h" #include "pyjp.h" JPMethod::JPMethod(JPJavaFrame& frame, JPClass* claz, const string& name, jobject mth, jmethodID mid, JPMethodList& moreSpecific, jint modifiers) : m_Method(frame, mth) { m_Class = claz; m_Name = name; m_MethodID = mid; m_MoreSpecificOverloads = moreSpecific; m_Modifiers = modifiers; m_ReturnType = (JPClass*) (-1); } JPMethod::~JPMethod() { } void JPMethod::setParameters( JPClass *returnType, JPClassList parameterTypes) { m_ReturnType = returnType; m_ParameterTypes = parameterTypes; } string JPMethod::toString() const { return m_Name; } JPMatch::Type matchVars(JPJavaFrame &frame, JPMethodMatch& match, JPPyObjectVector &arg, size_t start, JPClass *vartype) { JP_TRACE_IN("JPMethod::matchVars"); JPArrayClass *arraytype = (JPArrayClass*) vartype; JPClass *type = arraytype->getComponentType(); size_t len = arg.size(); JPMatch::Type lastMatch = JPMatch::_exact; for (size_t i = start; i < len; i++) { JPMatch::Type quality = type->findJavaConversion(match[i]); if (quality < JPMatch::_implicit) { return JPMatch::_none; } if (quality < lastMatch) { lastMatch = quality; } } return lastMatch; JP_TRACE_OUT; // GCOVR_EXCL_LINE } JPMatch::Type JPMethod::matches(JPJavaFrame &frame, JPMethodMatch& methodMatch, bool callInstance, JPPyObjectVector& arg) { ensureTypeCache(); JP_TRACE_IN("JPMethod::matches"); methodMatch.m_Overload = this; methodMatch.m_Offset = 0; methodMatch.m_Skip = 0; methodMatch.m_IsVarIndirect = false; methodMatch.m_Type = JPMatch::_exact; size_t len = arg.size(); size_t tlen = m_ParameterTypes.size(); JP_TRACE("Flags", isStatic(), isInstance(), callInstance); JP_TRACE("arguments length", len); JP_TRACE("types length", tlen); if (callInstance && isStatic()) { JP_TRACE("Skip this"); len--; methodMatch.m_Offset = 1; } if (callInstance || isInstance()) { JP_TRACE("Take this"); methodMatch.m_Skip = 1; } if (!JPModifier::isVarArgs(m_Modifiers)) { // Bypass if length does not match if (len != tlen) { JP_TRACE("Argument length mismatch", len, tlen); return methodMatch.m_Type = JPMatch::_none; } } else { JP_TRACE("Match vargs"); methodMatch.m_Type = JPMatch::_none; if (len < tlen - 1) { return methodMatch.m_Type; } JPClass* type = m_ParameterTypes[tlen - 1]; // Hard, could be direct array or an array. if (len == tlen) { // Try direct size_t last = tlen - 1 - methodMatch.m_Offset; methodMatch.m_Type = type->findJavaConversion(methodMatch.m_Arguments[last]); JP_TRACE("Direct vargs", methodMatch.m_Type); } if (methodMatch.m_Type < JPMatch::_implicit && len >= tlen) { // Must match the array type methodMatch.m_Type = matchVars(frame, methodMatch, arg, tlen - 1 + methodMatch.m_Offset, type); methodMatch.m_IsVarIndirect = true; JP_TRACE("Indirect vargs", methodMatch.m_Type); } else if (len < tlen) { methodMatch.m_IsVarIndirect = true; methodMatch.m_Type = JPMatch::_exact; JP_TRACE("Empty vargs"); } len = tlen - 1; if (methodMatch.m_Type < JPMatch::_implicit) { return methodMatch.m_Type; } } JP_TRACE("Match args"); for (size_t i = 0; i < len; i++) { size_t j = i + methodMatch.m_Offset; JPClass *type = m_ParameterTypes[i]; JPMatch::Type ematch = type->findJavaConversion(methodMatch.m_Arguments[j]); JP_TRACE("Result", ematch); if (ematch < methodMatch.m_Type) { methodMatch.m_Type = ematch; } if (methodMatch.m_Type < JPMatch::_implicit) { return methodMatch.m_Type; } } return methodMatch.m_Type; JP_TRACE_OUT; // GCOVR_EXCL_LINE } void JPMethod::packArgs(JPJavaFrame &frame, JPMethodMatch &match, vector &v, JPPyObjectVector &arg) { JP_TRACE_IN("JPMethod::packArgs"); size_t len = arg.size(); size_t tlen = m_ParameterTypes.size(); JP_TRACE("skip", match.m_Skip == 1); JP_TRACE("offset", match.m_Offset == 1); JP_TRACE("arguments length", len); JP_TRACE("types length", tlen); if (match.m_IsVarIndirect) { JP_TRACE("Pack indirect varargs"); len = tlen - 1; JPArrayClass* type = (JPArrayClass*) m_ParameterTypes[tlen - 1]; v[tlen - 1 - match.m_Skip] = type->convertToJavaVector(frame, arg, (jsize) tlen - 1, (jsize) arg.size()); } JP_TRACE("Pack fixed total=", len - match.m_Offset); for (size_t i = match.m_Skip; i < len; i++) { v[i - match.m_Skip] = match.m_Arguments[i].convert(); } JP_TRACE_OUT; // GCOVR_EXCL_LINE } JPPyObject JPMethod::invoke(JPJavaFrame& frame, JPMethodMatch& match, JPPyObjectVector& arg, bool instance) { JP_TRACE_IN("JPMethod::invoke"); // Check if it is caller sensitive if (isCallerSensitive()) return invokeCallerSensitive(match, arg, instance); size_t alen = m_ParameterTypes.size(); JPClass* retType = m_ReturnType; // Pack the arguments vector v(alen + 1); packArgs(frame, match, v, arg); // Invoke the method (arg[0] = this) if (JPModifier::isStatic(m_Modifiers)) { JP_TRACE("invoke static", m_Name); jclass claz = m_Class->getJavaClass(); return retType->invokeStatic(frame, claz, m_MethodID, &v[0]); } else { JPValue* selfObj = PyJPValue_getJavaSlot(arg[0]); jobject c; if (selfObj == NULL) { // This only can be hit by calling an instance method as a // class object. We already know it is safe to convert. jvalue v = match.m_Arguments[0].convert(); c = v.l; } else { c = selfObj->getJavaObject(); } jclass clazz = NULL; if (!isAbstract() && !instance) { clazz = m_Class->getJavaClass(); JP_TRACE("invoke nonvirtual", m_Name); } else { JP_TRACE("invoke virtual", m_Name); } return retType->invoke(frame, c, clazz, m_MethodID, &v[0]); } JP_TRACE_OUT; // GCOVR_EXCL_LINE } JPPyObject JPMethod::invokeCallerSensitive(JPMethodMatch& match, JPPyObjectVector& arg, bool instance) { JP_TRACE_IN("JPMethod::invokeCallerSensitive"); JPContext *context = m_Class->getContext(); size_t alen = m_ParameterTypes.size(); JPJavaFrame frame = JPJavaFrame::outer(context, (int) (8 + alen)); JPClass* retType = m_ReturnType; // Pack the arguments vector v(alen + 1); packArgs(frame, match, v, arg); //Proxy the call to // public static Object callMethod(Method method, Object obj, Object[] args) jobject self = NULL; size_t len = alen; if (!isStatic()) { JP_TRACE("Call instance"); len--; JPValue *selfObj = PyJPValue_getJavaSlot(arg[0]); if (selfObj == NULL) JP_RAISE(PyExc_RuntimeError, "Null object"); // GCOVR_EXCL_LINE self = selfObj->getJavaObject(); } // Convert arguments jobjectArray ja = frame.NewObjectArray((jsize) len, context->_java_lang_Object->getJavaClass(), NULL); for (jsize i = 0; i < (jsize) len; ++i) { JPClass *cls = m_ParameterTypes[i + match.m_Skip - match.m_Offset]; if (cls->isPrimitive()) { JPPrimitiveType* type = (JPPrimitiveType*) cls; PyObject *u = arg[i + match.m_Skip]; JPMatch conv(&frame, u); JPClass *boxed = type->getBoxedClass(context); boxed->findJavaConversion(conv); jvalue v = conv.convert(); frame.SetObjectArrayElement(ja, i, v.l); } else { frame.SetObjectArrayElement(ja, i, v[i].l); } } // Call the method jobject o; { JPPyCallRelease call; o = frame.callMethod(m_Method.get(), self, ja); } JP_TRACE("ReturnType", retType->getCanonicalName()); // Deal with the return if (retType->isPrimitive()) { JP_TRACE("Return primitive"); JPClass *boxed = ((JPPrimitiveType*) retType)->getBoxedClass(context); JPValue out = retType->getValueFromObject(JPValue(boxed, o)); return retType->convertToPythonObject(frame, out.getValue(), false); } else { JP_TRACE("Return object"); jvalue v; v.l = o; return retType->convertToPythonObject(frame, v, false); } JP_TRACE_OUT; } JPValue JPMethod::invokeConstructor(JPJavaFrame& frame, JPMethodMatch& match, JPPyObjectVector& arg) { JP_TRACE_IN("JPMethod::invokeConstructor"); size_t alen = m_ParameterTypes.size(); vector v(alen + 1); packArgs(frame, match, v, arg); JPPyCallRelease call; return JPValue(m_Class, frame.NewObjectA(m_Class->getJavaClass(), m_MethodID, &v[0])); JP_TRACE_OUT; // GCOVR_EXCL_LINE } string JPMethod::matchReport(JPPyObjectVector& args) { ensureTypeCache(); JPContext *context = m_Class->getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); stringstream res; res << m_ReturnType->getCanonicalName() << " ("; bool isFirst = true; for (vector::iterator it = m_ParameterTypes.begin(); it != m_ParameterTypes.end(); it++) { if (isFirst && !isStatic()) { isFirst = false; continue; } isFirst = false; res << (*it)->getCanonicalName(); } res << ") ==> "; JPMethodMatch methodMatch(frame, args, false); matches(frame, methodMatch, !isStatic(), args); // GCOVR_EXCL_START switch (methodMatch.m_Type) { case JPMatch::_none: res << "NONE"; break; case JPMatch::_explicit: res << "EXPLICIT"; break; case JPMatch::_implicit: res << "IMPLICIT"; break; case JPMatch::_exact: res << "EXACT"; break; default: res << "UNKNOWN"; break; } // GCOVR_EXCL_STOP res << endl; return res.str(); } bool JPMethod::checkMoreSpecificThan(JPMethod* other) const { for (JPMethodList::const_iterator it = m_MoreSpecificOverloads.begin(); it != m_MoreSpecificOverloads.end(); ++it) { if (other == *it) return true; } return false; } void JPMethod::ensureTypeCache() { if (m_ReturnType != (JPClass*) (-1)) return; m_Class->getContext()->getTypeManager()->populateMethod(this, m_Method.get()); } jpype-1.3.0/native/common/jp_methoddispatch.cpp000066400000000000000000000161151405671516700216350ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include #include "jpype.h" #include "jp_method.h" #include "jp_methoddispatch.h" JPMethodDispatch::JPMethodDispatch(JPClass* clazz, const string& name, JPMethodList& overloads, jint modifiers) : m_Name(name) { m_Class = clazz; m_Overloads = overloads; m_Modifiers = modifiers; m_LastCache.m_Hash = -1; } JPMethodDispatch::~JPMethodDispatch() { } const string& JPMethodDispatch::getName() const { return m_Name; } bool JPMethodDispatch::findOverload(JPJavaFrame& frame, JPMethodMatch &bestMatch, JPPyObjectVector& arg, bool callInstance, bool raise) { JP_TRACE_IN("JPMethodDispatch::findOverload"); JP_TRACE("Checking overload", m_Name); JP_TRACE("Got overloads to check", m_Overloads.size()); JPMethodList ambiguous; // Check cache to see if we already resolved this overload. // First we need to see if the hash matches for the last set of arguments. // Then make sure we don't hit the rare case that the hash was -1 by chance. // Then make sure it isn't variadic list match, as the hash of an opaque list // element can't be resolved without going through the resolution process. if (m_LastCache.m_Hash == bestMatch.m_Hash && m_LastCache.m_Overload != 0 && !m_LastCache.m_Overload->isVarArgs()) { bestMatch.m_Overload = m_LastCache.m_Overload; bestMatch.m_Overload->matches(frame, bestMatch, callInstance, arg); // Anything better than explicit constitutes a hit on the cache if (bestMatch.m_Type > JPMatch::_explicit) return true; } // We need two copies of the match. One to hold the best match we have // found, and one to hold the test of the next overload. JPMethodMatch match = bestMatch; // Check each overload in order (the TypeManager orders them by priority // according to Java overload rules). for (JPMethodList::iterator it = m_Overloads.begin(); it != m_Overloads.end(); ++it) { JPMethod* current = *it; JP_TRACE("Trying to match", current->toString()); current->matches(frame, match, callInstance, arg); JP_TRACE(" match ended", match.m_Type); if (match.m_Type == JPMatch::_exact) { // We can bypass the process here as there is no better match than exact. bestMatch = match; m_LastCache = (JPMethodCache&) match; // lgtm [cpp/slicing] return true; } if (match.m_Type < JPMatch::_implicit) continue; // If this is the first match then make it the best. if (bestMatch.m_Overload == 0) { bestMatch = match; continue; } // If the best does not hide the other, than we have ambiguity. if (!(bestMatch.m_Overload->checkMoreSpecificThan(current))) { // See if we can match based on instance if (callInstance == !current->isStatic()) { // if current matches instance and best does not switch if (callInstance == bestMatch.m_Overload->isStatic()) { bestMatch = match; continue; } } else { // if best matches instance and current does not, no ambiguity if (callInstance == !bestMatch.m_Overload->isStatic()) { continue; } } JP_TRACE("Adding to ambiguous list"); // Keep trace of ambiguous overloads for the error report. ambiguous.push_back(*it); } } // If we have an ambiguous overload report an error. if (!ambiguous.empty()) { if (!raise) return false; ambiguous.push_back(bestMatch.m_Overload); // We have two possible overloads so we declare an error std::stringstream ss; if (JPModifier::isConstructor(m_Modifiers)) ss << "Ambiguous overloads found for constructor " << m_Class->getCanonicalName() << "("; else ss << "Ambiguous overloads found for " << m_Class->getCanonicalName() << "." << getName() << "("; size_t start = callInstance ? 1 : 0; for (size_t i = start; i < arg.size(); ++i) { if (i != start) ss << ","; ss << Py_TYPE(arg[i])->tp_name; } ss << ")" << " between:" << std::endl; for (vector::iterator it = ambiguous.begin(); it != ambiguous.end(); ++it) { ss << "\t" << (*it)->toString() << std::endl; } JP_RAISE(PyExc_TypeError, ss.str()); JP_TRACE(ss.str()); } // If we can't find a matching overload throw an error. if (!bestMatch.m_Overload) { if (!raise) return false; std::stringstream ss; if (JPModifier::isConstructor(m_Modifiers)) ss << "No matching overloads found for constructor " << m_Class->getCanonicalName() << "("; else { ss << "No matching overloads found for "; if (!callInstance) ss << "*static* "; ss << m_Class->getCanonicalName() << "." << getName() << "("; } size_t start = callInstance ? 1 : 0; for (size_t i = start; i < arg.size(); ++i) { if (i != start) ss << ","; ss << Py_TYPE(arg[i])->tp_name; } ss << ")" << ", options are:" << std::endl; for (JPMethodList::iterator it = m_Overloads.begin(); it != m_Overloads.end(); ++it) { JPMethod* current = *it; ss << "\t" << current->toString(); ss << std::endl; } JP_RAISE(PyExc_TypeError, ss.str()); } // Set up a cache to bypass repeated calls. if (bestMatch.m_Type == JPMatch::_implicit) { m_LastCache = (JPMethodCache&) bestMatch; // lgtm [cpp/slicing] } JP_TRACE("Best match", bestMatch.m_Overload->toString()); return true; JP_TRACE_OUT; } JPPyObject JPMethodDispatch::invoke(JPJavaFrame& frame, JPPyObjectVector& args, bool instance) { JP_TRACE_IN("JPMethodDispatch::invoke"); JPMethodMatch match(frame, args, instance); findOverload(frame, match, args, instance, true); return match.m_Overload->invoke(frame, match, args, instance); JP_TRACE_OUT; } JPValue JPMethodDispatch::invokeConstructor(JPJavaFrame& frame, JPPyObjectVector& args) { JP_TRACE_IN("JPMethodDispatch::invokeConstructor"); JPMethodMatch match(frame, args, false); findOverload(frame, match, args, false, true); return match.m_Overload->invokeConstructor(frame, match, args); JP_TRACE_OUT; } bool JPMethodDispatch::matches(JPJavaFrame& frame, JPPyObjectVector& args, bool instance) { JP_TRACE_IN("JPMethodDispatch::invoke"); JPMethodMatch match(frame, args, instance); return findOverload(frame, match, args, instance, false); JP_TRACE_OUT; // GCOVR_EXCL_LINE } string JPMethodDispatch::matchReport(JPPyObjectVector& args) { stringstream res; res << "Match report for method " << m_Name << ", has " << m_Overloads.size() << " overloads." << endl; for (JPMethodList::iterator cur = m_Overloads.begin(); cur != m_Overloads.end(); cur++) { JPMethod* current = *cur; res << " " << current->matchReport(args); } return res.str(); } jpype-1.3.0/native/common/jp_monitor.cpp000066400000000000000000000023701405671516700203220ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "jp_monitor.h" JPMonitor::JPMonitor(JPContext* context, jobject value) : m_Value(context, value) { m_Context = context; } JPMonitor::~JPMonitor() { } void JPMonitor::enter() { // This can hold off for a while so we need to release resource // so that we don't dead lock. JPPyCallRelease call; JPJavaFrame frame = JPJavaFrame::outer(m_Context); frame.MonitorEnter(m_Value.get()); } void JPMonitor::exit() { JPJavaFrame frame = JPJavaFrame::outer(m_Context); frame.MonitorExit(m_Value.get()); } jpype-1.3.0/native/common/jp_numbertype.cpp000066400000000000000000000035771405671516700210370ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "pyjp.h" #include "jp_numbertype.h" JPNumberType::JPNumberType(JPJavaFrame& frame, jclass clss, const string& name, JPClass* super, JPClassList& interfaces, jint modifiers) : JPClass(frame, clss, name, super, interfaces, modifiers) { } JPNumberType::~JPNumberType() { } JPMatch::Type JPNumberType::findJavaConversion(JPMatch& match) { // Rules for java.lang.Object JP_TRACE_IN("JPNumberType::canConvertToJava"); if (nullConversion->matches(this, match) || javaNumberAnyConversion->matches(this, match) || boxLongConversion->matches(this, match) || boxDoubleConversion->matches(this, match) || hintsConversion->matches(this, match) ) return match.type; return match.type = JPMatch::_none; JP_TRACE_OUT; } void JPNumberType::getConversionInfo(JPConversionInfo &info) { JP_TRACE_IN("JPNumberType::getConversionInfo"); JPJavaFrame frame = JPJavaFrame::outer(m_Context); javaNumberAnyConversion->getInfo(this, info); boxLongConversion->getInfo(this, info); boxDoubleConversion->getInfo(this, info); hintsConversion->getInfo(this, info); PyList_Append(info.ret, PyJPClass_create(frame, this).get()); JP_TRACE_OUT; }jpype-1.3.0/native/common/jp_objecttype.cpp000066400000000000000000000043661405671516700210120ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "pyjp.h" #include "jp_objecttype.h" JPObjectType::JPObjectType(JPJavaFrame& frame, jclass clss, const string& name, JPClass* super, JPClassList& interfaces, jint modifiers) : JPClass(frame, clss, name, super, interfaces, modifiers) { } JPObjectType::~JPObjectType() { } JPMatch::Type JPObjectType::findJavaConversion(JPMatch& match) { // Rules for java.lang.Object JP_TRACE_IN("JPObjectType::canConvertToJava"); if (nullConversion->matches(this, match) || javaObjectAnyConversion->matches(this, match) || stringConversion->matches(this, match) || boxBooleanConversion->matches(this, match) || boxLongConversion->matches(this, match) || boxDoubleConversion->matches(this, match) || classConversion->matches(this, match) || proxyConversion->matches(this, match) || hintsConversion->matches(this, match) ) return match.type; return match.type = JPMatch::_none; JP_TRACE_OUT; } void JPObjectType::getConversionInfo(JPConversionInfo &info) { JP_TRACE_IN("JPObjectType::getConversionInfo"); JPJavaFrame frame = JPJavaFrame::outer(m_Context); nullConversion->getInfo(this, info); objectConversion->getInfo(this, info); stringConversion->getInfo(this, info); boxBooleanConversion->getInfo(this, info); boxLongConversion->getInfo(this, info); boxDoubleConversion->getInfo(this, info); classConversion->getInfo(this, info); proxyConversion->getInfo(this, info); hintsConversion->getInfo(this, info); PyList_Append(info.ret, PyJPClass_create(frame, this).get()); JP_TRACE_OUT; }jpype-1.3.0/native/common/jp_platform.cpp000066400000000000000000000102431405671516700204550ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "jp_platform.h" JPPlatformAdapter::~JPPlatformAdapter() { } #ifdef WIN32 #include /** * Windows-specific platform adapter */ class Win32PlatformAdapter : public JPPlatformAdapter { private: HINSTANCE jvmLibrary; std::string formatMessage(DWORD msgCode) { LPVOID lpMsgBuf; DWORD rc = ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, msgCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) & lpMsgBuf, 0, NULL ); // Fail to get format if (rc == 0) { std::stringstream ss; ss << "error code " << msgCode; return ss.str(); } std::string res((LPTSTR) lpMsgBuf); LocalFree(lpMsgBuf); return res; } public: virtual void loadLibrary(const char* path) override { JP_TRACE_IN("Win32PlatformAdapter::loadLibrary"); jvmLibrary = LoadLibrary(path); if (jvmLibrary == NULL) { JP_RAISE_OS_ERROR_WINDOWS( GetLastError(), path); } JP_TRACE_OUT; } virtual void unloadLibrary() override { // on success return code is nonzero, TODO: handle error? FreeLibrary(jvmLibrary); } virtual void* getSymbol(const char* name) override { void* res = (void*) GetProcAddress(jvmLibrary, name); if (res == NULL) { std::stringstream msg; msg << "Unable to load symbol [" << name << "], error = " << formatMessage(GetLastError()); JP_RAISE(PyExc_RuntimeError, msg.str().c_str()); } return res; } } ; #define PLATFORM_ADAPTER Win32PlatformAdapter #else #if defined(_HPUX) && !defined(_IA64) #include #else #include #endif // HPUX #include // The code in this modules is mostly excluded from coverage as it is only // possible to execute during a fatal error. class LinuxPlatformAdapter : public JPPlatformAdapter { private: void* jvmLibrary; public: virtual void loadLibrary(const char* path) override { JP_TRACE_IN("LinuxPlatformAdapter::loadLibrary"); #if defined(_HPUX) && !defined(_IA64) JP_TRACE("shl_load", path); jvmLibrary = shl_load(path, BIND_DEFERRED | BIND_VERBOSE, 0L); #else JP_TRACE("dlopen", path); jvmLibrary = dlopen(path, RTLD_LAZY | RTLD_GLOBAL); #endif // HPUX // GCOVR_EXCL_START if (jvmLibrary == NULL) { JP_TRACE("null library"); JP_TRACE("errno", errno); if (errno == ENOEXEC) { JP_TRACE("dignostics", dlerror()); } JP_RAISE_OS_ERROR_UNIX( errno, path); } // GCOVR_EXCL_STOP JP_TRACE_OUT; // GCOVR_EXCL_LINE } virtual void unloadLibrary() override { JP_TRACE_IN("LinuxPlatformAdapter::unloadLibrary"); int r = dlclose(jvmLibrary); // GCOVR_EXCL_START if (r != 0) // error { cerr << dlerror() << endl; } // GCOVR_EXCL_STOP JP_TRACE_OUT; // GCOVR_EXCL_LINE } virtual void* getSymbol(const char* name) override { JP_TRACE_IN("LinuxPlatformAdapter::getSymbol"); JP_TRACE("Load", name); void* res = dlsym(jvmLibrary, name); JP_TRACE("Res", res); // GCOVR_EXCL_START if (res == NULL) { JP_TRACE("errno", errno); std::stringstream msg; msg << "Unable to load symbol [" << name << "], error = " << dlerror(); JP_RAISE(PyExc_RuntimeError, msg.str().c_str()); } // GCOVR_EXCL_STOP return res; JP_TRACE_OUT; // GCOVR_EXCL_LINE } } ; #define PLATFORM_ADAPTER LinuxPlatformAdapter #endif namespace { PLATFORM_ADAPTER* adapter; } JPPlatformAdapter* JPPlatformAdapter::getAdapter() { if (adapter == NULL) adapter = new PLATFORM_ADAPTER(); return adapter; } jpype-1.3.0/native/common/jp_primitivetype.cpp000066400000000000000000000027031405671516700215450ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" JPPrimitiveType::JPPrimitiveType(const string& name) : JPClass(name, 0x411) { } JPPrimitiveType::~JPPrimitiveType() { } bool JPPrimitiveType::isPrimitive() const { return true; } // equivalent of long_subtype_new as it isn't exposed PyObject *JPPrimitiveType::convertLong(PyTypeObject* wrapper, PyLongObject* tmp) { if (wrapper == NULL) JP_RAISE(PyExc_SystemError, "bad wrapper"); Py_ssize_t n = Py_SIZE(tmp); if (n < 0) n = -n; PyLongObject *newobj = (PyLongObject *) wrapper->tp_alloc(wrapper, n); if (newobj == NULL) return NULL; ((PyVarObject*) newobj)->ob_size = Py_SIZE(tmp); for (Py_ssize_t i = 0; i < n; i++) { newobj->ob_digit[i] = tmp->ob_digit[i]; } return (PyObject*) newobj; } jpype-1.3.0/native/common/jp_proxy.cpp000066400000000000000000000217551405671516700200240ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "pyjp.h" #include "jp_proxy.h" #include "jp_classloader.h" #include "jp_reference_queue.h" #include "jp_primitive_accessor.h" #include "jp_boxedtype.h" #include "jp_functional.h" JPPyObject getArgs(JPContext* context, jlongArray parameterTypePtrs, jobjectArray args) { JP_TRACE_IN("JProxy::getArgs"); JPJavaFrame frame = JPJavaFrame::outer(context); jsize argLen = frame.GetArrayLength(parameterTypePtrs); JPPyObject pyargs = JPPyObject::call(PyTuple_New(argLen)); JPPrimitiveArrayAccessor accessor(frame, parameterTypePtrs, &JPJavaFrame::GetLongArrayElements, &JPJavaFrame::ReleaseLongArrayElements); jlong* types = accessor.get(); for (jsize i = 0; i < argLen; i++) { jobject obj = frame.GetObjectArrayElement(args, i); JPClass* type = frame.findClassForObject(obj); if (type == NULL) type = reinterpret_cast (types[i]); JPValue val = type->getValueFromObject(JPValue(type, obj)); PyTuple_SetItem(pyargs.get(), i, type->convertToPythonObject(frame, val, false).keep()); } return pyargs; JP_TRACE_OUT; } extern "C" JNIEXPORT jobject JNICALL Java_org_jpype_proxy_JPypeProxy_hostInvoke( JNIEnv *env, jclass clazz, jlong contextPtr, jstring name, jlong hostObj, jlong returnTypePtr, jlongArray parameterTypePtrs, jobjectArray args) { JPContext* context = (JPContext*) contextPtr; JPJavaFrame frame = JPJavaFrame::external(context, env); // We need the resources to be held for the full duration of the proxy. JPPyCallAcquire callback; { JP_TRACE_IN("JPype_InvocationHandler_hostInvoke"); JP_TRACE("context", context); JP_TRACE("hostObj", (void*) hostObj); try { // GCOVR_EXCL_START // Sanity check, should never be hit if (hostObj == 0) { env->functions->ThrowNew(env, context->m_RuntimeException.get(), "host reference is null"); return NULL; } // GCOVR_EXCL_STOP string cname = frame.toStringUTF8(name); JP_TRACE("Get callable for", cname); // Get the callable object JPPyObject callable(((JPProxy*) hostObj)->getCallable(cname)); // If method can't be called, throw an exception if (callable.isNull() || callable.get() == Py_None) { JP_TRACE("Callable not found"); JP_RAISE_METHOD_NOT_FOUND(cname); return NULL; } // Find the return type JPClass* returnClass = (JPClass*) returnTypePtr; JP_TRACE("Get return type", returnClass->getCanonicalName()); // convert the arguments into a python list JP_TRACE("Convert arguments"); JPPyObject pyargs = getArgs(context, parameterTypePtrs, args); JP_TRACE("Call Python"); JPPyObject returnValue = JPPyObject::call(PyObject_Call(callable.get(), pyargs.get(), NULL)); JP_TRACE("Handle return", Py_TYPE(returnValue.get())->tp_name); if (returnClass == context->_void) { JP_TRACE("Void return"); return NULL; } // This is a SystemError where the caller return null without // setting a Python error. if (returnValue.isNull()) { JP_TRACE("Null return"); JP_RAISE(PyExc_TypeError, "Return value is null when it cannot be"); } // We must box here. JPMatch returnMatch(&frame, returnValue.get()); if (returnClass->isPrimitive()) { JP_TRACE("Box return"); if (returnClass->findJavaConversion(returnMatch) == JPMatch::_none) JP_RAISE(PyExc_TypeError, "Return value is not compatible with required type."); jvalue res = returnMatch.convert(); JPBoxedType *boxed = (JPBoxedType *) ((JPPrimitiveType*) returnClass)->getBoxedClass(context); jvalue res2; res2.l = boxed->box(frame, res); return frame.keep(res2.l); } if (returnClass->findJavaConversion(returnMatch) == JPMatch::_none) { JP_TRACE("Cannot convert"); JP_RAISE(PyExc_TypeError, "Return value is not compatible with required type."); } JP_TRACE("Convert return to", returnClass->getCanonicalName()); jvalue res = returnMatch.convert(); return frame.keep(res.l); } catch (JPypeException& ex) { JP_TRACE("JPypeException raised"); ex.toJava(context); } catch (...) // GCOVR_EXCL_LINE { JP_TRACE("Other Exception raised"); env->functions->ThrowNew(env, context->m_RuntimeException.get(), "unknown error occurred"); } return NULL; JP_TRACE_OUT; // GCOVR_EXCL_LINE } } JPProxy::JPProxy(JPContext* context, PyJPProxy* inst, JPClassList& intf) : m_Context(context), m_Instance(inst), m_InterfaceClasses(intf) { JP_TRACE_IN("JPProxy::JPProxy"); JP_TRACE("Context", m_Context); JPJavaFrame frame = JPJavaFrame::outer(m_Context); // Convert the interfaces to a Class[] jobjectArray ar = frame.NewObjectArray((int) intf.size(), m_Context->_java_lang_Class->getJavaClass(), NULL); for (unsigned int i = 0; i < intf.size(); i++) { frame.SetObjectArrayElement(ar, i, intf[i]->getJavaClass()); } jvalue v[4]; v[0].l = m_Context->getJavaContext(); v[1].j = (jlong) this; v[2].j = (jlong) & JPProxy::releaseProxyPython; v[3].l = ar; // Create the proxy jobject proxy = frame.CallStaticObjectMethodA(context->m_ProxyClass.get(), context->m_Proxy_NewID, v); m_Proxy = JPObjectRef(m_Context, proxy); m_Ref = NULL; JP_TRACE_OUT; } JPProxy::~JPProxy() { try { if (m_Ref != NULL && m_Context->isRunning()) { m_Context->getEnv()->DeleteWeakGlobalRef(m_Ref); } } catch (JPypeException &ex) // GCOVR_EXCL_LINE { // Cannot throw } } void JPProxy::releaseProxyPython(void* host) { Py_XDECREF(((JPProxy*) host)->m_Instance); } jvalue JPProxy::getProxy() { JP_TRACE_IN("JPProxy::getProxy"); JPContext* context = getContext(); JPJavaFrame frame = JPJavaFrame::inner(context); jobject instance = NULL; if (m_Ref != NULL) { instance = frame.NewLocalRef(m_Ref); } if (instance == NULL) { // Use the proxy to make an instance JP_TRACE("Create handler"); Py_INCREF(m_Instance); instance = frame.CallObjectMethodA(m_Proxy.get(), m_Context->m_Proxy_NewInstanceID, 0); m_Ref = frame.NewWeakGlobalRef(instance); } jvalue out; out.l = frame.keep(instance); return out; JP_TRACE_OUT; } JPProxyType::JPProxyType(JPJavaFrame& frame, jclass clss, const string& name, JPClass* super, JPClassList& interfaces, jint modifiers) : JPClass(frame, clss, name, super, interfaces, modifiers) { jclass proxyClass = frame.FindClass("java/lang/reflect/Proxy"); m_ProxyClass = JPClassRef(frame, proxyClass); m_GetInvocationHandlerID = frame.GetStaticMethodID(proxyClass, "getInvocationHandler", "(Ljava/lang/Object;)Ljava/lang/reflect/InvocationHandler;"); m_InstanceID = frame.GetFieldID(clss, "instance", "J"); } JPProxyType::~JPProxyType() { } JPPyObject JPProxyType::convertToPythonObject(JPJavaFrame& frame, jvalue val, bool cast) { JP_TRACE_IN("JPProxyType::convertToPythonObject"); jobject ih = frame.CallStaticObjectMethodA(m_ProxyClass.get(), m_GetInvocationHandlerID, &val); PyJPProxy *target = ((JPProxy*) frame.GetLongField(ih, m_InstanceID))->m_Instance; if (target->m_Target != Py_None && target->m_Convert) return JPPyObject::use(target->m_Target); JP_TRACE("Target", target); return JPPyObject::use((PyObject*) target); JP_TRACE_OUT; // GCOVR_EXCL_LINE } JPProxyDirect::JPProxyDirect(JPContext* context, PyJPProxy* inst, JPClassList& intf) : JPProxy(context, inst, intf) { } JPProxyDirect::~JPProxyDirect() { } JPPyObject JPProxyDirect::getCallable(const string& cname) { return JPPyObject::accept(PyObject_GetAttrString((PyObject*) m_Instance, cname.c_str())); } JPProxyIndirect::JPProxyIndirect(JPContext* context, PyJPProxy* inst, JPClassList& intf) : JPProxy(context, inst, intf) { } JPProxyIndirect::~JPProxyIndirect() { } JPPyObject JPProxyIndirect::getCallable(const string& cname) { JPPyObject out = JPPyObject::accept(PyObject_GetAttrString(m_Instance->m_Target, cname.c_str())); if (!out.isNull()) return out; return JPPyObject::accept(PyObject_GetAttrString((PyObject*) m_Instance, cname.c_str())); } JPProxyFunctional::JPProxyFunctional(JPContext* context, PyJPProxy* inst, JPClassList& intf) : JPProxy(context, inst, intf) { m_Functional = (JPFunctional*) intf[0]; } JPProxyFunctional::~JPProxyFunctional() { } JPPyObject JPProxyFunctional::getCallable(const string& cname) { if (cname == m_Functional->getMethod()) return JPPyObject::accept(PyObject_GetAttrString(m_Instance->m_Target, "__call__")); return JPPyObject::accept(PyObject_GetAttrString((PyObject*) m_Instance, cname.c_str())); } jpype-1.3.0/native/common/jp_reference_queue.cpp000066400000000000000000000061371405671516700220020ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include #include #include "jpype.h" #include "jp_classloader.h" #include "jp_reference_queue.h" #include "jp_gc.h" #include "pyjp.h" static jobject s_ReferenceQueue = NULL; static jmethodID s_ReferenceQueueRegisterMethod = NULL; extern "C" { static void releasePython(void* host) { Py_XDECREF((PyObject*) host); } /* * Class: org_jpype_ref_JPypeReferenceQueue * Method: init * Signature: (Ljava/lang/Object;Ljava/lang/reflect/Method;)V */ JNIEXPORT void JNICALL Java_org_jpype_ref_JPypeReferenceNative_init (JNIEnv *env, jclass clazz, jobject refqueue, jobject registerID) { s_ReferenceQueue = env->NewGlobalRef(refqueue); s_ReferenceQueueRegisterMethod = env->FromReflectedMethod(registerID); } JNIEXPORT void JNICALL Java_org_jpype_ref_JPypeReferenceNative_removeHostReference (JNIEnv *env, jclass, jlong host, jlong cleanup) { JPContext* context = JPContext_global; // Exceptions are not allowed here try { JPJavaFrame frame = JPJavaFrame::external((JPContext*) context, env); JPPyCallAcquire callback; if (cleanup != 0) { JCleanupHook func = (JCleanupHook) cleanup; (*func)((void*) host); } } catch (...) // GCOVR_EXCL_LINE { } } /** Triggered whenever the sentinel is deleted */ JNIEXPORT void JNICALL Java_org_jpype_ref_JPypeReferenceNative_wake (JNIEnv *env, jclass clazz) { // Exceptions are not allowed here try { JPContext* context = JPContext_global; context->m_GC->triggered(); } catch (...) // GCOVR_EXCL_LINE { } } } void JPReferenceQueue::registerRef(JPJavaFrame &frame, jobject obj, PyObject* hostRef) { // There are certain calls such as exception handling in which the // Python object is null. In those cases, we don't need to bind the Java // object lifespan and can just ignore it. if (hostRef == 0) return; // MATCH TO DECREF IN releasePython Py_INCREF(hostRef); registerRef(frame, obj, hostRef, &releasePython); } void JPReferenceQueue::registerRef(JPJavaFrame &frame, jobject obj, void* host, JCleanupHook func) { JP_TRACE_IN("JPReferenceQueue::registerRef"); // create the ref ... jvalue args[3]; args[0].l = obj; args[1].j = (jlong) host; args[2].j = (jlong) func; if (s_ReferenceQueue == NULL) JP_RAISE(PyExc_SystemError, "Memory queue not installed"); JP_TRACE("Register reference"); frame.CallVoidMethodA(s_ReferenceQueue, s_ReferenceQueueRegisterMethod, args); JP_TRACE_OUT; // GCOVR_EXCL_LINE } jpype-1.3.0/native/common/jp_shorttype.cpp000066400000000000000000000220561405671516700206770ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "pyjp.h" #include "jp_array.h" #include "jp_primitive_accessor.h" #include "jp_shorttype.h" JPShortType::JPShortType() : JPPrimitiveType("short") { } JPShortType::~JPShortType() { } JPPyObject JPShortType::convertToPythonObject(JPJavaFrame& frame, jvalue val, bool cast) { JPPyObject tmp = JPPyObject::call(PyLong_FromLong(field(val))); JPPyObject out = JPPyObject::call(convertLong(getHost(), (PyLongObject*) tmp.get())); PyJPValue_assignJavaSlot(frame, out.get(), JPValue(this, val)); return out; } JPValue JPShortType::getValueFromObject(const JPValue& obj) { JPContext *context = obj.getClass()->getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); jvalue v; jobject jo = obj.getValue().l; JPBoxedType* jb = (JPBoxedType*) frame.findClassForObject(jo); field(v) = (type_t) frame.CallIntMethodA(jo, jb->m_IntValueID, 0); return JPValue(this, v); } JPConversionLong shortConversion; JPConversionLongNumber shortNumberConversion; JPConversionLongWiden shortWidenConversion; class JPConversionJShort : public JPConversionJavaValue { public: virtual JPMatch::Type matches(JPClass *cls, JPMatch &match) override { JPValue* value = match.getJavaSlot(); if (value == NULL) return JPMatch::_none; match.type = JPMatch::_none; // Implied conversion from boxed to primitive (JLS 5.1.8) if (javaValueConversion->matches(cls, match) || unboxConversion->matches(cls, match)) return match.type; // Consider widening JPClass *cls2 = value->getClass(); if (cls2->isPrimitive()) { // https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.2 JPPrimitiveType *prim = (JPPrimitiveType*) cls2; switch (prim->getTypeCode()) { case 'C': case 'B': match.conversion = &shortWidenConversion; return match.type = JPMatch::_implicit; default: break; } } // Unboxing must be to the from the exact boxed type (JLS 5.1.8) return JPMatch::_implicit; //short cut further checks } virtual void getInfo(JPClass *cls, JPConversionInfo &info) override { JPContext *context = cls->getContext(); PyList_Append(info.exact, (PyObject*) context->_short->getHost()); PyList_Append(info.implicit, (PyObject*) context->_byte->getHost()); PyList_Append(info.implicit, (PyObject*) context->_char->getHost()); unboxConversion->getInfo(cls, info); } } jshortConversion; JPMatch::Type JPShortType::findJavaConversion(JPMatch &match) { JP_TRACE_IN("JPShortType::findJavaConversion"); if (match.object == Py_None) return match.type = JPMatch::_none; if (jshortConversion.matches(this, match) || shortConversion.matches(this, match) || shortNumberConversion.matches(this, match)) return match.type; return match.type = JPMatch::_none; JP_TRACE_OUT; } void JPShortType::getConversionInfo(JPConversionInfo &info) { JPJavaFrame frame = JPJavaFrame::outer(m_Context); jshortConversion.getInfo(this, info); shortConversion.getInfo(this, info); shortNumberConversion.getInfo(this, info); PyList_Append(info.ret, (PyObject*) m_Context->_short->getHost()); } jarray JPShortType::newArrayOf(JPJavaFrame& frame, jsize sz) { return frame.NewShortArray(sz); } JPPyObject JPShortType::getStaticField(JPJavaFrame& frame, jclass c, jfieldID fid) { jvalue v; field(v) = frame.GetStaticShortField(c, fid); return convertToPythonObject(frame, v, false); } JPPyObject JPShortType::getField(JPJavaFrame& frame, jobject c, jfieldID fid) { jvalue v; field(v) = frame.GetShortField(c, fid); return convertToPythonObject(frame, v, false); } JPPyObject JPShortType::invokeStatic(JPJavaFrame& frame, jclass claz, jmethodID mth, jvalue* val) { jvalue v; { JPPyCallRelease call; field(v) = frame.CallStaticShortMethodA(claz, mth, val); } return convertToPythonObject(frame, v, false); } JPPyObject JPShortType::invoke(JPJavaFrame& frame, jobject obj, jclass clazz, jmethodID mth, jvalue* val) { jvalue v; { JPPyCallRelease call; if (clazz == NULL) field(v) = frame.CallShortMethodA(obj, mth, val); else field(v) = frame.CallNonvirtualShortMethodA(obj, clazz, mth, val); } return convertToPythonObject(frame, v, false); } void JPShortType::setStaticField(JPJavaFrame& frame, jclass c, jfieldID fid, PyObject* obj) { JPMatch match(&frame, obj); if (findJavaConversion(match) < JPMatch::_implicit) JP_RAISE(PyExc_TypeError, "Unable to convert to Java short"); type_t val = field(match.convert()); frame.SetStaticShortField(c, fid, val); } void JPShortType::setField(JPJavaFrame& frame, jobject c, jfieldID fid, PyObject* obj) { JPMatch match(&frame, obj); if (findJavaConversion(match) < JPMatch::_implicit) JP_RAISE(PyExc_TypeError, "Unable to convert to Java short"); type_t val = field(match.convert()); frame.SetShortField(c, fid, val); } void JPShortType::setArrayRange(JPJavaFrame& frame, jarray a, jsize start, jsize length, jsize step, PyObject* sequence) { JP_TRACE_IN("JPShortType::setArrayRange"); JPPrimitiveArrayAccessor accessor(frame, a, &JPJavaFrame::GetShortArrayElements, &JPJavaFrame::ReleaseShortArrayElements); type_t* val = accessor.get(); // First check if assigning sequence supports buffer API if (PyObject_CheckBuffer(sequence)) { JPPyBuffer buffer(sequence, PyBUF_FULL_RO); if (buffer.valid()) { Py_buffer& view = buffer.getView(); if (view.ndim != 1) JP_RAISE(PyExc_TypeError, "buffer dims incorrect"); Py_ssize_t vshape = view.shape[0]; Py_ssize_t vstep = view.strides[0]; if (vshape != length) JP_RAISE(PyExc_ValueError, "mismatched size"); char* memory = (char*) view.buf; if (view.suboffsets && view.suboffsets[0] >= 0) memory = *((char**) memory) + view.suboffsets[0]; jsize index = start; jconverter conv = getConverter(view.format, (int) view.itemsize, "s"); for (Py_ssize_t i = 0; i < length; ++i, index += step) { jvalue r = conv(memory); val[index] = r.s; memory += vstep; } accessor.commit(); return; } else { PyErr_Clear(); } } // Use sequence API JPPySequence seq = JPPySequence::use(sequence); jsize index = start; for (Py_ssize_t i = 0; i < length; ++i, index += step) { PyObject *item = seq[i].get(); if (!PyIndex_Check(item)) { PyErr_Format(PyExc_TypeError, "Unable to implicitly convert '%s' to short", Py_TYPE(item)->tp_name); JP_RAISE_PYTHON(); } jlong v = PyLong_AsLongLong(item); if (v == -1) JP_PY_CHECK(); val[index] = (type_t) assertRange(v); } accessor.commit(); JP_TRACE_OUT; } JPPyObject JPShortType::getArrayItem(JPJavaFrame& frame, jarray a, jsize ndx) { array_t array = (array_t) a; type_t val; frame.GetShortArrayRegion(array, ndx, 1, &val); jvalue v; field(v) = val; return convertToPythonObject(frame, v, false); } void JPShortType::setArrayItem(JPJavaFrame& frame, jarray a, jsize ndx, PyObject* obj) { JPMatch match(&frame, obj); if (findJavaConversion(match) < JPMatch::_implicit) JP_RAISE(PyExc_TypeError, "Unable to convert to Java short"); type_t val = field(match.convert()); frame.SetShortArrayRegion((array_t) a, ndx, 1, &val); } void JPShortType::getView(JPArrayView& view) { JPJavaFrame frame = JPJavaFrame::outer(view.getContext()); view.m_Memory = (void*) frame.GetShortArrayElements( (jshortArray) view.m_Array->getJava(), &view.m_IsCopy); view.m_Buffer.format = "h"; view.m_Buffer.itemsize = sizeof (jshort); } void JPShortType::releaseView(JPArrayView& view) { try { JPJavaFrame frame = JPJavaFrame::outer(view.getContext()); frame.ReleaseShortArrayElements((jshortArray) view.m_Array->getJava(), (jshort*) view.m_Memory, view.m_Buffer.readonly ? JNI_ABORT : 0); } catch (JPypeException&) { // This is called as part of the cleanup routine and exceptions // are not permitted } } const char* JPShortType::getBufferFormat() { return "h"; } ssize_t JPShortType::getItemSize() { return sizeof (jshort); } void JPShortType::copyElements(JPJavaFrame &frame, jarray a, jsize start, jsize len, void* memory, int offset) { jshort* b = (jshort*) ((char*) memory + offset); frame.GetShortArrayRegion((jshortArray) a, start, len, b); } static void pack(jshort* d, jvalue v) { *d = v.s; } PyObject *JPShortType::newMultiArray(JPJavaFrame &frame, JPPyBuffer &buffer, int subs, int base, jobject dims) { JP_TRACE_IN("JPShortType::newMultiArray"); return convertMultiArray( frame, this, &pack, "s", buffer, subs, base, dims); JP_TRACE_OUT; } jpype-1.3.0/native/common/jp_stringtype.cpp000066400000000000000000000054111405671516700210420ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "pyjp.h" #include "jp_stringtype.h" JPStringType::JPStringType(JPJavaFrame& frame, jclass clss, const string& name, JPClass* super, JPClassList& interfaces, jint modifiers) : JPClass(frame, clss, name, super, interfaces, modifiers) { } JPStringType::~JPStringType() { } JPPyObject JPStringType::convertToPythonObject(JPJavaFrame& frame, jvalue val, bool cast) { JP_TRACE_IN("JPStringType::asHostObject"); JPContext *context = frame.getContext(); if (!cast) { // This loses type if (val.l == NULL) { return JPPyObject::getNone(); } if (context->getConvertStrings()) { string str = frame.toStringUTF8((jstring) (val.l)); return JPPyObject::call(PyUnicode_FromString(str.c_str())); } } return JPClass::convertToPythonObject(frame, val, cast); JP_TRACE_OUT; // GCOV_EXCL_LINE } JPMatch::Type JPStringType::findJavaConversion(JPMatch& match) { JP_TRACE_IN("JPStringType::findJavaConversion"); if (nullConversion->matches(this, match) || objectConversion->matches(this, match) || stringConversion->matches(this, match) || hintsConversion->matches(this, match) ) return match.type; return match.type = JPMatch::_none; JP_TRACE_OUT; // GCOV_EXCL_LINE } void JPStringType::getConversionInfo(JPConversionInfo &info) { JPJavaFrame frame = JPJavaFrame::outer(m_Context); objectConversion->getInfo(this, info); stringConversion->getInfo(this, info); hintsConversion->getInfo(this, info); if (m_Context->getConvertStrings()) PyList_Append(info.ret, (PyObject*) & PyUnicode_Type); // GCOVR_EXCL_LINE else PyList_Append(info.ret, (PyObject*) getHost()); } JPValue JPStringType::newInstance(JPJavaFrame& frame, JPPyObjectVector& args) { JP_TRACE_IN("JPStringType::newInstance"); if (args.size() == 1 && JPPyString::check(args[0])) { // JNI has a short cut for constructing java.lang.String JP_TRACE("Direct"); string str = JPPyString::asStringUTF8(args[0]); return JPValue(this, frame.fromStringUTF8(str)); } return JPClass::newInstance(frame, args); JP_TRACE_OUT; // GCOV_EXCL_LINE } jpype-1.3.0/native/common/jp_tracer.cpp000066400000000000000000000111501405671516700201070ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include #include "jpype.h" #include "jp_tracer.h" // GCOVR_EXCL_START #if defined(_MSC_VER) && _MSC_VER<1700 // Welcome to the year 2008! namespace std { class mutex { } ; template class lock_guard { public: lock_guard(const T& mutex_type) { } } ; } #else #include #endif static int jpype_traceLevel = 0; static JPypeTracer* jpype_tracer_last = NULL; std::mutex trace_lock; #define JPYPE_TRACING_OUTPUT cerr static int INDENT_WIDTH = 2; static const char *INDENT = " "; static void jpype_indent(int space) { space *= INDENT_WIDTH; while (space > 80) { JPYPE_TRACING_OUTPUT << INDENT; space -= 80; } JPYPE_TRACING_OUTPUT << &INDENT[80 - space]; } //This code is not thread safe, thus tracing a multithreaded code is likely // to result in crashes. JPypeTracer::JPypeTracer(const char* name, void* reference) : m_Name(name) { m_Error = false; m_Last = jpype_tracer_last; jpype_tracer_last = this; traceIn(name, reference); } JPypeTracer::~JPypeTracer() { traceOut(m_Name.c_str(), m_Error); jpype_tracer_last = m_Last; } void JPypeTracer::traceIn(const char* msg, void* ref) { if (_PyJPModule_trace == 0) return; if (jpype_traceLevel < 0) jpype_traceLevel = 0; std::lock_guard guard(trace_lock); jpype_indent(jpype_traceLevel); JPYPE_TRACING_OUTPUT << "> " << msg ; if (ref != NULL) JPYPE_TRACING_OUTPUT << " id=\"" << ref << "\""; JPYPE_TRACING_OUTPUT << endl; JPYPE_TRACING_OUTPUT.flush(); jpype_traceLevel++; } void JPypeTracer::traceOut(const char* msg, bool error) { if (_PyJPModule_trace == 0) return; std::lock_guard guard(trace_lock); jpype_traceLevel--; jpype_indent(jpype_traceLevel); if (error) { JPYPE_TRACING_OUTPUT << "EXCEPTION! " << msg << endl; } else { JPYPE_TRACING_OUTPUT << "< " << msg << endl; } JPYPE_TRACING_OUTPUT.flush(); } void JPypeTracer::traceJavaObject(const char* msg, const void* ref) { if ((_PyJPModule_trace & 4) == 0) return; if (ref == (void*) 0) { JPypeTracer::trace1("JNI", msg); return; } if (ref == (void*) - 1) { JPypeTracer::trace1("+ JNI", msg); jpype_traceLevel++; return; } if (ref == (void*) - 2) { jpype_traceLevel--; JPypeTracer::trace1("- JNI", msg); return; } stringstream str; str << msg << " " << (void*) ref ; JPypeTracer::trace1("JNI", str.str().c_str()); } void JPypeTracer::tracePythonObject(const char* msg, PyObject* ref) { if ((_PyJPModule_trace & 2) == 0) return; if (ref != NULL) { stringstream str; str << msg << " " << (void*) ref << " " << ref->ob_refcnt << " " << Py_TYPE(ref)->tp_name; JPypeTracer::trace1("PY", str.str().c_str()); } else { stringstream str; str << msg << " " << (void*) ref; JPypeTracer::trace1("PY", str.str().c_str()); } } void JPypeTracer::trace1(const char* source, const char* msg) { if (_PyJPModule_trace == 0) return; std::lock_guard guard(trace_lock); string name = "unknown"; if (jpype_tracer_last != NULL) name = jpype_tracer_last->m_Name; jpype_indent(jpype_traceLevel); if (source != NULL) JPYPE_TRACING_OUTPUT << source << ": "; if (source == NULL || (_PyJPModule_trace & 16) != 0) JPYPE_TRACING_OUTPUT << name << ": "; JPYPE_TRACING_OUTPUT << msg << endl; JPYPE_TRACING_OUTPUT.flush(); } void JPypeTracer::trace2(const char* msg1, const char* msg2) { if (_PyJPModule_trace == 0) return; std::lock_guard guard(trace_lock); string name = "unknown"; if (jpype_tracer_last != NULL) name = jpype_tracer_last->m_Name; jpype_indent(jpype_traceLevel); JPYPE_TRACING_OUTPUT << name << ": " << msg1 << " " << msg2 << endl; JPYPE_TRACING_OUTPUT.flush(); } void JPypeTracer::traceLocks(const string& msg, void* ref) { std::lock_guard guard(trace_lock); JPYPE_TRACING_OUTPUT << msg << ": " << ref << endl; JPYPE_TRACING_OUTPUT.flush(); } // GCOVR_EXCL_STOPjpype-1.3.0/native/common/jp_typefactory.cpp000066400000000000000000000333451405671516700212120ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "pyjp.h" #include "jp_primitive_accessor.h" #include "jp_classloader.h" #include "jp_boxedtype.h" #include "jp_field.h" #include "jp_objecttype.h" #include "jp_numbertype.h" #include "jp_classtype.h" #include "jp_method.h" #include "jp_methoddispatch.h" #include "jp_buffertype.h" #include "jp_typemanager.h" #include "jp_arrayclass.h" #include "jp_stringtype.h" #include "jp_voidtype.h" #include "jp_booleantype.h" #include "jp_bytetype.h" #include "jp_chartype.h" #include "jp_shorttype.h" #include "jp_inttype.h" #include "jp_longtype.h" #include "jp_floattype.h" #include "jp_doubletype.h" #include "jp_functional.h" #include "jp_proxy.h" void JPTypeFactory_rethrow(JPJavaFrame& frame) { try { throw; } catch (JPypeException& ex) { ex.toJava(frame.getContext()); } catch (...) // GCOVR_EXCL_LINE { // GCOVR_EXCL_START frame.ThrowNew(frame.getContext()->m_RuntimeException.get(), "unknown error occurred"); // GCOVR_EXCL_STOP } } template void convert(JPJavaFrame& frame, jlongArray array, vector& out) { JPPrimitiveArrayAccessor accessor(frame, array, &JPJavaFrame::GetLongArrayElements, &JPJavaFrame::ReleaseLongArrayElements); jlong* values = accessor.get(); jsize sz = frame.GetArrayLength(array); out.resize(sz); for (int i = 0; i < sz; ++i) { out[i] = (T) values[i]; } return; } #ifdef JP_TRACING_ENABLE #define JP_JAVA_TRY(...) \ JPypeTracer _trace(__VA_ARGS__); \ try { #define JP_JAVA_CATCH(...) \ } \ catch(...) { \ _trace.gotError(JP_STACKINFO()); \ JPTypeFactory_rethrow(frame); } return __VA_ARGS__ #else #define JP_JAVA_TRY(...) try { #define JP_JAVA_CATCH(...) } catch(...) { JPTypeFactory_rethrow(frame); } return __VA_ARGS__ #endif extern "C" { JNIEXPORT void JNICALL Java_org_jpype_manager_TypeFactoryNative_newWrapper( JNIEnv *env, jobject self, jlong contextPtr, jlong jcls) { JPContext* context = (JPContext*) contextPtr; JPJavaFrame frame = JPJavaFrame::external(context, env); JP_JAVA_TRY("JPTypeFactory_newWrapper"); JPPyCallAcquire callback; JPClass* cls = (JPClass*) jcls; PyJPClass_hook(frame, cls); JP_JAVA_CATCH(); // GCOVR_EXCL_LINE } JNIEXPORT void JNICALL Java_org_jpype_manager_TypeFactoryNative_destroy( JNIEnv *env, jobject self, jlong contextPtr, jlongArray resources, jint sz) { JPContext* context = (JPContext*) contextPtr; JPJavaFrame frame = JPJavaFrame::external(context, env); JP_JAVA_TRY("JPTypeFactory_destroy"); JPPrimitiveArrayAccessor accessor(frame, resources, &JPJavaFrame::GetLongArrayElements, &JPJavaFrame::ReleaseLongArrayElements); jlong* values = accessor.get(); for (int i = 0; i < sz; ++i) { context->m_Resources.push_back((JPResource*) values[i]); } return; JP_JAVA_CATCH(); // GCOVR_EXCL_LINE } JNIEXPORT jlong JNICALL Java_org_jpype_manager_TypeFactoryNative_defineMethodDispatch( JNIEnv *env, jobject self, jlong contextPtr, jlong clsPtr, jstring name, jlongArray overloadPtrs, jint modifiers) { JPContext* context = (JPContext*) contextPtr; JPJavaFrame frame = JPJavaFrame::external(context, env); JP_JAVA_TRY("JPTypeFactory_defineMethodDispatch"); JPClass* cls = (JPClass*) clsPtr; JPMethodList overloadList; convert(frame, overloadPtrs, overloadList); string cname = frame.toStringUTF8(name); JP_TRACE(cname); JPMethodDispatch* dispatch = new JPMethodDispatch(cls, cname, overloadList, modifiers); return (jlong) dispatch; JP_JAVA_CATCH(0); // GCOVR_EXCL_LINE } JNIEXPORT jlong JNICALL Java_org_jpype_manager_TypeFactoryNative_defineArrayClass( JNIEnv *env, jobject self, jlong contextPtr, jclass cls, jstring name, jlong superClass, jlong componentClass, jint modifiers) { JPContext* context = (JPContext*) contextPtr; JPJavaFrame frame = JPJavaFrame::external(context, env); JP_JAVA_TRY("JPTypeFactory_defineArrayClass"); string cname = frame.toStringUTF8(name); JP_TRACE(cname); JPArrayClass* result = new JPArrayClass(frame, cls, cname, (JPClass*) superClass, (JPClass*) componentClass, modifiers); return (jlong) result; JP_JAVA_CATCH(0); // GCOVR_EXCL_LINE } JNIEXPORT jlong JNICALL Java_org_jpype_manager_TypeFactoryNative_defineObjectClass( JNIEnv *env, jobject self, jlong contextPtr, jclass cls, jstring name, jlong superClass, jlongArray interfacePtrs, jint modifiers) { // All resources are created here are owned by Java and deleted by Java shutdown routine JPContext* context = (JPContext*) contextPtr; JPJavaFrame frame = JPJavaFrame::external(context, env); JP_JAVA_TRY("JPTypeFactory_defineObjectClass"); string className = frame.toStringUTF8(name); JP_TRACE(className); JPClassList interfaces; if (interfacePtrs != NULL) convert(frame, interfacePtrs, interfaces); JPClass* result = NULL; if (!JPModifier::isSpecial(modifiers)) { // Create a normal class return (jlong) new JPClass(frame, cls, className, (JPClass*) superClass, interfaces, modifiers); } if (JPModifier::isFunctional(modifiers)) return (jlong) new JPFunctional(frame, cls, className, (JPClass*) superClass, interfaces, modifiers); if (JPModifier::isBuffer(modifiers)) return (jlong) new JPBufferType(frame, cls, className, (JPClass*) superClass, interfaces, modifiers); // Certain classes require special implementations if (className == "java.lang.Object") return (jlong) (context->_java_lang_Object = new JPObjectType(frame, cls, className, (JPClass*) superClass, interfaces, modifiers)); if (className == "java.lang.Class") return (jlong) (context->_java_lang_Class = new JPClassType(frame, cls, className, (JPClass*) superClass, interfaces, modifiers)); if (className == "java.lang.CharSequence") return (jlong) (new JPStringType(frame, cls, className, (JPClass*) superClass, interfaces, modifiers)); if (className == "java.lang.String") return (jlong) (context->_java_lang_String = new JPStringType(frame, cls, className, (JPClass*) superClass, interfaces, modifiers)); if (className == "java.lang.Throwable") return (jlong) (context->_java_lang_Throwable = new JPClassType(frame, cls, className, (JPClass*) superClass, interfaces, modifiers)); if (className == "java.lang.Number") return (jlong) new JPNumberType(frame, cls, className, (JPClass*) superClass, interfaces, modifiers); // Register the box types if (className == "java.lang.Void") { context->_void = new JPVoidType(); return (jlong) (context->_java_lang_Void = new JPBoxedType(frame, cls, className, (JPClass*) superClass, interfaces, modifiers, context->_void)); } if (className == "java.lang.Boolean") { context->_boolean = new JPBooleanType(); return (jlong) (context->_java_lang_Boolean = new JPBoxedType(frame, cls, className, (JPClass*) superClass, interfaces, modifiers, context->_boolean)); } if (className == "java.lang.Byte") { context->_byte = new JPByteType(); return (jlong) (context->_java_lang_Byte = new JPBoxedType(frame, cls, className, (JPClass*) superClass, interfaces, modifiers, context->_byte)); } if (className == "java.lang.Character") { context->_char = new JPCharType(); return (jlong) (context->_java_lang_Character = new JPBoxedType(frame, cls, className, (JPClass*) superClass, interfaces, modifiers, context->_char)); } if (className == "java.lang.Short") { context->_short = new JPShortType(); return (jlong) (context->_java_lang_Short = new JPBoxedType(frame, cls, className, (JPClass*) superClass, interfaces, modifiers, context->_short)); } if (className == "java.lang.Integer") { context->_int = new JPIntType(); return (jlong) (context->_java_lang_Integer = new JPBoxedType(frame, cls, className, (JPClass*) superClass, interfaces, modifiers, context->_int)); } if (className == "java.lang.Long") { context->_long = new JPLongType(); return (jlong) (context->_java_lang_Long = new JPBoxedType(frame, cls, className, (JPClass*) superClass, interfaces, modifiers, context->_long)); } if (className == "java.lang.Float") { context->_float = new JPFloatType(); return (jlong) (context->_java_lang_Float = new JPBoxedType(frame, cls, className, (JPClass*) superClass, interfaces, modifiers, context->_float)); } if (className == "java.lang.Double") { context->_double = new JPDoubleType(); return (jlong) (context->_java_lang_Double = new JPBoxedType(frame, cls, className, (JPClass*) superClass, interfaces, modifiers, context->_double)); } if (className == "org.jpype.proxy.JPypeProxy") return (jlong) new JPProxyType(frame, cls, className, (JPClass*) superClass, interfaces, modifiers); // Register reflection types for later use if (className == "java.lang.reflect.Method") return (jlong) (context->_java_lang_reflect_Method = new JPClass(frame, cls, className, (JPClass*) superClass, interfaces, modifiers)); if (className == "java.lang.reflect.Field") return (jlong) (context->_java_lang_reflect_Field = new JPClass(frame, cls, className, (JPClass*) superClass, interfaces, modifiers)); stringstream ss; ss << "Special class not defined for " << className; JP_RAISE(PyExc_RuntimeError, ss.str()); return (jlong) result; JP_JAVA_CATCH(0); // GCOVR_EXCL_LINE } JNIEXPORT jlong JNICALL Java_org_jpype_manager_TypeFactoryNative_definePrimitive( JNIEnv *env, jobject self, jlong contextPtr, jstring name, jclass cls, jlong boxedPtr, jint modifiers) { // These resources are created by the boxed types JPContext* context = (JPContext*) contextPtr; JPJavaFrame frame = JPJavaFrame::external(context, env); JP_JAVA_TRY("JPTypeFactory_definePrimitive"); string cname = frame.toStringUTF8(name); JP_TRACE(cname); if (cname == "void") { context->_void->setClass(frame, cls); return (jlong) (context->_void); } if (cname == "byte") { context->_byte->setClass(frame, cls); return (jlong) (context->_byte); } if (cname == "boolean") { context->_boolean->setClass(frame, cls); return (jlong) (context->_boolean); } if (cname == "char") { context->_char->setClass(frame, cls); return (jlong) (context->_char); } if (cname == "short") { context->_short->setClass(frame, cls); return (jlong) (context->_short); } if (cname == "int") { context->_int->setClass(frame, cls); return (jlong) (context->_int); } if (cname == "long") { context->_long->setClass(frame, cls); return (jlong) (context->_long); } if (cname == "float") { context->_float->setClass(frame, cls); return (jlong) (context->_float); } if (cname == "double") { context->_double->setClass(frame, cls); return (jlong) (context->_double); } return 0; JP_JAVA_CATCH(0); // GCOVR_EXCL_LINE } JNIEXPORT void JNICALL Java_org_jpype_manager_TypeFactoryNative_assignMembers( JNIEnv *env, jobject self, jlong contextPtr, jlong clsPtr, jlong ctorMethod, jlongArray methodPtrs, jlongArray fieldPtrs) { JPContext* context = (JPContext*) contextPtr; JPJavaFrame frame = JPJavaFrame::external(context, env); JP_JAVA_TRY("JPTypeFactory_assignMembers"); JPClass* cls = (JPClass*) clsPtr; JPMethodDispatchList methodList; convert(frame, methodPtrs, methodList); JPFieldList fieldList; convert(frame, fieldPtrs, fieldList); cls->assignMembers( (JPMethodDispatch*) ctorMethod, methodList, fieldList); return; JP_JAVA_CATCH(); // GCOVR_EXCL_LINE } JNIEXPORT jlong JNICALL Java_org_jpype_manager_TypeFactoryNative_defineField( JNIEnv *env, jobject self, jlong contextPtr, jlong cls, jstring name, jobject field, jlong fieldType, jint modifiers) { JPContext* context = (JPContext*) contextPtr; JPJavaFrame frame = JPJavaFrame::external(context, env); JP_JAVA_TRY("JPTypeFactory_defineField"); string cname = frame.toStringUTF8(name); JP_TRACE("class", cls); JP_TRACE(cname); jfieldID fid = frame.FromReflectedField(field); return (jlong) (new JPField( frame, (JPClass*) cls, cname, field, fid, (JPClass*) fieldType, modifiers)); JP_JAVA_CATCH(0); // GCOVR_EXCL_LINE } JNIEXPORT jlong JNICALL Java_org_jpype_manager_TypeFactoryNative_defineMethod( JNIEnv *env, jobject self, jlong contextPtr, jlong cls, jstring name, jobject method, jlongArray overloadList, jint modifiers) { JPContext* context = (JPContext*) contextPtr; JPJavaFrame frame = JPJavaFrame::external(context, env); JP_JAVA_TRY("JPTypeFactory_defineMethod"); jmethodID mid = frame.FromReflectedMethod(method); JPMethodList cover; convert(frame, overloadList, cover); string cname = frame.toStringUTF8(name); JP_TRACE(cname); return (jlong) (new JPMethod( frame, (JPClass*) cls, cname, method, mid, cover, modifiers)); JP_JAVA_CATCH(0); } JNIEXPORT void JNICALL Java_org_jpype_manager_TypeFactoryNative_populateMethod( JNIEnv *env, jobject self, jlong contextPtr, jlong method, jlong returnType, jlongArray argumentTypes ) { JPContext* context = (JPContext*) contextPtr; JPJavaFrame frame = JPJavaFrame::external(context, env); JP_JAVA_TRY("JPTypeFactory_populateMethod"); JPClassList cargs; convert(frame, argumentTypes, cargs); JPMethod *methodPtr = (JPMethod*) method; methodPtr->setParameters((JPClass*) returnType, cargs); JP_JAVA_CATCH(); // GCOVR_EXCL_LINE } } // extern "C" jpype-1.3.0/native/common/jp_typemanager.cpp000066400000000000000000000064571405671516700211610ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "jp_classloader.h" JPTypeManager::JPTypeManager(JPJavaFrame& frame) { JP_TRACE_IN("JPTypeManager::init"); m_Context = frame.getContext(); jclass cls = m_Context->getClassLoader()->findClass(frame, "org.jpype.manager.TypeManager"); m_FindClass = frame.GetMethodID(cls, "findClass", "(Ljava/lang/Class;)J"); m_FindClassByName = frame.GetMethodID(cls, "findClassByName", "(Ljava/lang/String;)J"); m_FindClassForObject = frame.GetMethodID(cls, "findClassForObject", "(Ljava/lang/Object;)J"); m_PopulateMethod = frame.GetMethodID(cls, "populateMethod", "(JLjava/lang/reflect/Executable;)V"); m_PopulateMembers = frame.GetMethodID(cls, "populateMembers", "(Ljava/lang/Class;)V"); // The object instance will be loaded later JP_TRACE_OUT; } JPTypeManager::~JPTypeManager() { } JPClass* JPTypeManager::findClass(jclass obj) { JP_TRACE_IN("JPTypeManager::findClass"); JPJavaFrame frame = JPJavaFrame::outer(m_Context); jvalue val; val.l = obj; return (JPClass*) (frame.CallLongMethodA(m_JavaTypeManager.get(), m_FindClass, &val)); JP_TRACE_OUT; } JPClass* JPTypeManager::findClassByName(const string& name) { JP_TRACE_IN("JPTypeManager::findClassByName"); JPJavaFrame frame = JPJavaFrame::outer(m_Context); jvalue val; val.l = (jobject) frame.fromStringUTF8(name); JPClass* out = (JPClass*) (frame.CallLongMethodA(m_JavaTypeManager.get(), m_FindClassByName, &val)); if (out == NULL) { stringstream err; err << "Class " << name << " is not found"; JP_RAISE(PyExc_TypeError, err.str().c_str()); } return out; JP_TRACE_OUT; } JPClass* JPTypeManager::findClassForObject(jobject obj) { JP_TRACE_IN("JPTypeManager::findClassForObject"); JPJavaFrame frame = JPJavaFrame::outer(m_Context); jvalue val; val.l = obj; JPClass *cls = (JPClass*) (frame.CallLongMethodA(m_JavaTypeManager.get(), m_FindClassForObject, &val)); frame.check(); JP_TRACE("ClassName", cls == NULL ? "null" : cls->getCanonicalName()); return cls; JP_TRACE_OUT; } void JPTypeManager::populateMethod(void* method, jobject obj) { JP_TRACE_IN("JPTypeManager::populateMethod"); JPJavaFrame frame = JPJavaFrame::outer(m_Context); jvalue val[2]; val[0].j = (jlong) method; val[1].l = obj; JP_TRACE("Method", method); frame.CallVoidMethodA(m_JavaTypeManager.get(), m_PopulateMethod, val); JP_TRACE_OUT; } void JPTypeManager::populateMembers(JPClass* cls) { JP_TRACE_IN("JPTypeManager::populateMembers"); JPJavaFrame frame = JPJavaFrame::outer(m_Context); jvalue val[1]; val[0].l = (jobject) cls->getJavaClass(); frame.CallVoidMethodA(m_JavaTypeManager.get(), m_PopulateMembers, val); JP_TRACE_OUT; } jpype-1.3.0/native/common/jp_value.cpp000066400000000000000000000023571405671516700177540ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include jobject JPValue::getJavaObject() const { // This is all sanity check // GCOVR_EXCL_START if (m_Class == NULL) JP_RAISE(PyExc_RuntimeError, "Null class"); if (!m_Class->isPrimitive()) // GCOVR_EXCL_STOP return m_Value.l; // This method is only used internally, thus it requires a logical code // error to trigger. We will use type error in case there is some // way a user can trigger it. JP_RAISE(PyExc_TypeError, "cannot access Java primitive value as Java object"); // GCOVR_EXCL_LINE } jpype-1.3.0/native/common/jp_voidtype.cpp000066400000000000000000000073431405671516700205030ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "jp_voidtype.h" JPVoidType::JPVoidType() : JPPrimitiveType("void") { } JPVoidType::~JPVoidType() { } JPPyObject JPVoidType::invokeStatic(JPJavaFrame& frame, jclass claz, jmethodID mth, jvalue* val) { { JPPyCallRelease call; frame.CallStaticVoidMethodA(claz, mth, val); } return JPPyObject::getNone(); } JPPyObject JPVoidType::invoke(JPJavaFrame& frame, jobject obj, jclass clazz, jmethodID mth, jvalue* val) { { JPPyCallRelease call; if (clazz == NULL) frame.CallVoidMethodA(obj, mth, val); else frame.CallNonvirtualVoidMethodA(obj, clazz, mth, val); } return JPPyObject::getNone(); } // GCOVR_EXCL_START JPValue JPVoidType::getValueFromObject(const JPValue& obj) { // This is needed if we call a caller sensitive method // and we get a return which is expected to be a void object JP_TRACE_IN("JPVoidType::getValueFromObject"); return JPValue(this, (jobject) 0); JP_TRACE_OUT; } JPPyObject JPVoidType::getStaticField(JPJavaFrame& frame, jclass c, jfieldID fid) { JP_RAISE(PyExc_SystemError, "void cannot be the type of a static field."); } JPPyObject JPVoidType::getField(JPJavaFrame& frame, jobject c, jfieldID fid) { JP_RAISE(PyExc_SystemError, "void cannot be the type of a field."); } JPPyObject JPVoidType::convertToPythonObject(JPJavaFrame& frame, jvalue val, bool cast) { return JPPyObject::getNone(); } JPMatch::Type JPVoidType::findJavaConversion(JPMatch &match) { return match.type = JPMatch::_none; } void JPVoidType::setStaticField(JPJavaFrame& frame, jclass c, jfieldID fid, PyObject*) { JP_RAISE(PyExc_SystemError, "void cannot be the type of a static field."); } void JPVoidType::setField(JPJavaFrame& frame, jobject c, jfieldID fid, PyObject*) { JP_RAISE(PyExc_SystemError, "void cannot be the type of a field."); } void JPVoidType::setArrayRange(JPJavaFrame& frame, jarray, jsize start, jsize length, jsize step, PyObject* sequence) { JP_RAISE(PyExc_SystemError, "void cannot be the type of an array."); } JPPyObject JPVoidType::getArrayItem(JPJavaFrame& frame, jarray, jsize) { JP_RAISE(PyExc_SystemError, "void cannot be the type of an array."); } void JPVoidType::setArrayItem(JPJavaFrame& frame, jarray, jsize, PyObject*) { JP_RAISE(PyExc_SystemError, "void cannot be the type of an array."); } jarray JPVoidType::newArrayOf(JPJavaFrame& frame, jsize) { JP_RAISE(PyExc_SystemError, "void cannot be the type of an array."); } void JPVoidType::getView(JPArrayView& view) { } void JPVoidType::releaseView(JPArrayView& view) { } const char* JPVoidType::getBufferFormat() { return NULL; } ssize_t JPVoidType::getItemSize() { return 0; } void JPVoidType::copyElements(JPJavaFrame &frame, jarray a, jsize start, jsize len, void* memory, int offset) { } char JPVoidType::getTypeCode() { return 'V'; } jlong JPVoidType::getAsLong(jvalue v) { return 0; } jdouble JPVoidType::getAsDouble(jvalue v) { return 0; } PyObject *JPVoidType::newMultiArray(JPJavaFrame &frame, JPPyBuffer& view, int subs, int base, jobject dims) { return NULL; } // GCOVR_EXCL_STOPjpype-1.3.0/native/java/000077500000000000000000000000001405671516700150655ustar00rootroot00000000000000jpype-1.3.0/native/java/org/000077500000000000000000000000001405671516700156545ustar00rootroot00000000000000jpype-1.3.0/native/java/org/jpype/000077500000000000000000000000001405671516700170035ustar00rootroot00000000000000jpype-1.3.0/native/java/org/jpype/JPypeContext.java000066400000000000000000000434011405671516700222440ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype; import java.io.File; import java.lang.reflect.Array; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.nio.Buffer; import java.nio.ByteOrder; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import org.jpype.classloader.DynamicClassLoader; import org.jpype.manager.TypeFactory; import org.jpype.manager.TypeFactoryNative; import org.jpype.manager.TypeManager; import org.jpype.pkg.JPypePackage; import org.jpype.pkg.JPypePackageManager; import org.jpype.ref.JPypeReferenceQueue; /** * Context for JPype. *

* This is the part of JPype that holds all resources. After the classloader is * created this class is given the address of the context object in JPype. Any * resources in JPype Java layer can be contacted using the context. *

* Boot order is - create the C++ portion of the context. - start the jvm - load * the bootloader - install the jar into the bootloader - install all native * methods using the bootloader - create the Java portion of the context. - use * the Java context to access the resources (ReferenceQueue, TypeFactory, * TypeManager) *

* Once started, python calls use the context to get a frame and attach their * threads. Methods called from Java will get the env and use it to get their * context from which they can create a frame. *

* The C++ context will hold all the previous global variables thus allowing the * C++ portion to be cleaned up properly when the JVM is shutdown or * disconnected. *

* As the JPypeContext can't be tested directly from Java code, it will need to * be kept light. *

* Our goal is to remove as much direct contact methods as possible from the C++ * layer. Previous globals in JPTypeManager move to the context as do the * contents of JPJni. * * * * @author nelson85 */ public class JPypeContext { public final String VERSION = "1.3.0"; private static JPypeContext INSTANCE = new JPypeContext(); // This is the C++ portion of the context. private long context; private TypeFactory typeFactory; private TypeManager typeManager; private DynamicClassLoader classLoader; private final AtomicInteger shutdownFlag = new AtomicInteger(); private final List shutdownHooks = new ArrayList<>(); private final List postHooks = new ArrayList<>(); public static boolean freeResources = true; static public JPypeContext getInstance() { return INSTANCE; } /** * Start the JPype system. * * @param context is the C++ portion of the context. * @param bootLoader is the classloader holding JPype resources. * @return the created context. */ static JPypeContext createContext(long context, ClassLoader bootLoader, String nativeLib, boolean interrupt) { if (nativeLib != null) { System.load(nativeLib); } INSTANCE.context = context; INSTANCE.classLoader = (DynamicClassLoader) bootLoader; INSTANCE.typeFactory = new TypeFactoryNative(); INSTANCE.typeManager = new TypeManager(context, INSTANCE.typeFactory); INSTANCE.initialize(interrupt); scanExistingJars(); return INSTANCE; } private JPypeContext() { } void initialize(boolean interrupt) { // Okay everything is setup so lets give it a go. this.typeManager.init(); JPypeReferenceQueue.getInstance().start(); if (!interrupt) JPypeSignal.installHandlers(); // Install a shutdown hook to clean up Python resources. Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { @Override public void run() { INSTANCE.shutdown(); } })); } /** * Shutdown and remove all Python resources. * * This hook is only called after the last user thread has died. Thus the only * remaining connections are proxies that were attached to the JVM shutdown * hook, the reference queue, and the typemanager. * * This routine will try to take out the last connections in an orderly * fashion. Inherently this is a very dangerous time as portions of Java have * already been deactivated. */ @SuppressWarnings( { "CallToThreadYield", "SleepWhileInLoop" }) private void shutdown() { try { // Try to yield in case there is a race condition. The user // may have installed a shutdown hook, but we cannot verify // the order that shutdown hook threads are executed. Thus we will // try to intentionally lose the race. // // This will only occur if something registered a shutdown hook through // a Java API. Those registered though the JPype API will be joined // manually. for (int i = 0; i < 5; i++) { try { Thread.sleep(1); Thread.yield(); } catch (InterruptedException ex) { } } // Execute any used defined shutdown hooks registered with JPype. if (!this.shutdownHooks.isEmpty()) { for (Thread thread : this.shutdownHooks) { thread.start(); } for (Thread thread : this.shutdownHooks) { try { thread.join(); } catch (InterruptedException ex) { } } } // Disable all future calls to proxies this.shutdownFlag.incrementAndGet(); // Past this point any further execution of a Python proxy would // be fatal. Thread t1 = Thread.currentThread(); Map threads = Thread.getAllStackTraces(); for (Thread t : threads.keySet()) { if (t1 == t || t.isDaemon()) continue; t.interrupt(); } // Inform Python no more calls are permitted onShutdown(this.context); Thread.yield(); // Wait for any unregistered proxies to finish so that we don't yank // the rug out from under them result in a segfault. // while (this.proxyCount.get() > 0) // { // try // { // Thread.sleep(10); // } catch (InterruptedException ex) // { // } // } // // Check to see if who is alive // threads = Thread.getAllStackTraces(); // System.out.println("Check for remaining"); // for (Thread t : threads.keySet()) // { // // Daemon threads don't count for shutdown so skip them. // if (t.isDaemon()) // continue; // System.out.println(" " + t.getName() + " " + t.getState() + " " + t.isDaemon()); // for (StackTraceElement e : t.getStackTrace()) // { // System.out.println(" " + e.getClassName()); // } // } } catch (Throwable th) { } if (freeResources) { // Release all Python references try { JPypeReferenceQueue.getInstance().stop(); } catch (Throwable th) { } // Release any C++ resources try { this.typeManager.shutdown(); } catch (Throwable th) { } } // Execute post hooks for (Runnable run : this.postHooks) { run.run(); } } static native void onShutdown(long ctxt); public void addShutdownHook(Thread th) { this.shutdownHooks.add(th); } public boolean removeShutdownHook(Thread th) { if (this.shutdownHooks.contains(th)) { this.shutdownHooks.remove(th); return true; } else return Runtime.getRuntime().removeShutdownHook(th); } /** * Get the C++ portion. * * @return */ public long getContext() { return context; } public ClassLoader getClassLoader() { return this.classLoader; } public TypeFactory getTypeFactory() { return this.typeFactory; } public TypeManager getTypeManager() { return this.typeManager; } /** * Add a hook to run after Python interface is shutdown. * * This must never have a Python method attached. * * @param run */ public void _addPost(Runnable run) { this.postHooks.add(run); } /** * Call a method using reflection.This method creates a stackframe so that * caller sensitive methods will execute properly. * * * @param method is the method to call. * @param obj is the object to operate on, it will be null if the method is * static. * @param args the arguments to method. * @return the object that results form the invocation. * @throws java.lang.Throwable throws whatever type the called method * produces. */ public Object callMethod(Method method, Object obj, Object[] args) throws Throwable { try { return method.invoke(obj, args); } catch (InvocationTargetException ex) { throw ex.getCause(); } } /** * Helper function for collect rectangular, */ private static boolean collect(List l, Object o, int q, int[] shape, int d) { if (Array.getLength(o) != shape[q]) return false; if (q + 1 == d) { l.add(o); return true; } for (int i = 0; i < shape[q]; ++i) { if (!collect(l, Array.get(o, i), q + 1, shape, d)) return false; } return true; } /** * Collect up a rectangular primitive array for a Python memory view. * * If it is a rectangular primitive array then the result will be an object * array containing. - the primitive type - an int array with the shape of the * array - each of the primitive arrays that will need be visited in order. * * This is the safest way to provide a view as we are verifying and collected * thus even if something mutates the shape of the array after we have * visited, we have a locked copy. * * @param o is the object to be tested. * @return null if the object is not a rectangular primitive array. */ public Object[] collectRectangular(Object o) { if (o == null || !o.getClass().isArray()) return null; int[] shape = new int[5]; int d = 0; ArrayList out = new ArrayList<>(); Object o1 = o; Class c1 = o1.getClass(); for (int i = 0; i < 5; ++i) { int l = Array.getLength(o1); if (l == 0) return null; shape[d++] = l; o1 = Array.get(o1, 0); if (o1 == null) return null; c1 = c1.getComponentType(); if (!c1.isArray()) break; } if (!c1.isPrimitive()) return null; out.add(c1); shape = Arrays.copyOfRange(shape, 0, d); out.add(shape); int total = 1; for (int i = 0; i < d - 1; i++) total *= shape[i]; out.ensureCapacity(total + 2); if (d == 5) return null; if (!collect(out, o, 0, shape, d)) return null; return out.toArray(); } private Object unpack(int size, Object parts) { Object e0 = Array.get(parts, 0); Class c = e0.getClass(); int segments = Array.getLength(parts) / size; Object a2 = Array.newInstance(c, size); Object a1 = Array.newInstance(a2.getClass(), segments); int k = 0; for (int i = 0; i < segments; i++) { for (int j = 0; j < size; j++, k++) { Object o = Array.get(parts, k); Array.set(a2, j, o); } Array.set(a1, i, a2); if (i < segments - 1) a2 = Array.newInstance(c, size); } return a1; } public Object assemble(int[] dims, Object parts) { int n = dims.length; if (n == 1) return Array.get(parts, 0); if (n == 2) return Array.get(unpack(dims[0], parts), 0); for (int i = 0; i < n - 2; ++i) { parts = unpack(dims[n - i - 2], parts); } return parts; } public boolean isShutdown() { return shutdownFlag.get() > 0; } // public void incrementProxy() // { // proxyCount.incrementAndGet(); // } // // public void decrementProxy() // { // proxyCount.decrementAndGet(); // } /** * Clear the current interrupt. * * @param x is true if an exception should be thrown. * @throws InterruptedException */ public static void clearInterrupt(boolean x) throws InterruptedException { try { Thread th = Thread.currentThread(); // Only relevant if this is the main thread for signal handling if (th != JPypeSignal.main) return; // Unconditionally clear the interrupt flag if we are called from // C++. This happens when a field get() or method call() is // invoked. if (!x) JPypeSignal.acknowledgePy(); // Check if this thread is interrupted if (th.isInterrupted()) { // Clear the flag in C++ JPypeSignal.acknowledgePy(); // Clear the flag in Java Thread.sleep(1); } } catch (InterruptedException ex) { if (x) throw ex; } } public long getExcClass(Throwable th) { if (th instanceof PyExceptionProxy) return ((PyExceptionProxy) th).cls; return 0; } public long getExcValue(Throwable th) { if (th instanceof PyExceptionProxy) return ((PyExceptionProxy) th).value; return 0; } public Exception createException(long l0, long l1) { return new PyExceptionProxy(l0, l1); } public boolean order(Buffer b) { if (b instanceof java.nio.ByteBuffer) return ((java.nio.ByteBuffer) b).order() == ByteOrder.LITTLE_ENDIAN; if (b instanceof java.nio.ShortBuffer) return ((java.nio.ShortBuffer) b).order() == ByteOrder.LITTLE_ENDIAN; if (b instanceof java.nio.CharBuffer) return ((java.nio.CharBuffer) b).order() == ByteOrder.LITTLE_ENDIAN; if (b instanceof java.nio.IntBuffer) return ((java.nio.IntBuffer) b).order() == ByteOrder.LITTLE_ENDIAN; if (b instanceof java.nio.LongBuffer) return ((java.nio.LongBuffer) b).order() == ByteOrder.LITTLE_ENDIAN; if (b instanceof java.nio.FloatBuffer) return ((java.nio.FloatBuffer) b).order() == ByteOrder.LITTLE_ENDIAN; if (b instanceof java.nio.DoubleBuffer) return ((java.nio.DoubleBuffer) b).order() == ByteOrder.LITTLE_ENDIAN; return true; } public boolean isPackage(String s) { s = JPypeKeywords.safepkg(s); return JPypePackageManager.isPackage(s); } public JPypePackage getPackage(String s) { s = JPypeKeywords.safepkg(s); if (!JPypePackageManager.isPackage(s)) return null; return new JPypePackage(s); } /** * Utility to probe functional interfaces. * * @param cls * @return */ public String getFunctional(Class cls) { // If we don't find it to be a functional interface, then we won't return // the SAM. if (cls.getDeclaredAnnotation(FunctionalInterface.class) == null) return null; for (Method m : cls.getMethods()) { if (Modifier.isAbstract(m.getModifiers())) { // This is a very odd construct. Java allows for java.lang.Object // methods to declared in FunctionalInterfaces and they don't count // towards the single abstract method. So we have to probe the class // until we find something that fails. try { Object.class.getMethod(m.getName(), m.getParameterTypes()); } catch (NoSuchMethodException | SecurityException ex) { return m.getName(); } } } return null; } /** * Utility function for extracting the unique portion of a stack trace. * * This is a bit different that the Java method which works from the back. We * will be using fake stacktraces from Python at some point so finding the * first common is a better approach. * * @param th is the throwable. * @param enclosing is the throwsble that holds this or null if top level. * @return the unique frames as an object array with 4 objects per frame. */ public Object[] getStackTrace(Throwable th, Throwable enclosing) { StackTraceElement[] trace = th.getStackTrace(); if (trace == null || enclosing == null) return toFrames(trace); StackTraceElement[] te = enclosing.getStackTrace(); if (te == null) return toFrames(trace); for (int i = 0; i < trace.length; ++i) { if (trace[i].equals(te[0])) { return toFrames(Arrays.copyOfRange(trace, 0, i)); } } return toFrames(trace); } private Object[] toFrames(StackTraceElement[] stackTrace) { if (stackTrace == null) return null; Object[] out = new Object[4 * stackTrace.length]; int i = 0; for (StackTraceElement fr : stackTrace) { out[i++] = fr.getClassName(); out[i++] = fr.getMethodName(); out[i++] = fr.getFileName(); out[i++] = fr.getLineNumber(); } return out; } public void newWrapper(long l) { // We can only go through this point single file. synchronized (this.typeFactory) { this.typeFactory.newWrapper(context, l); } } private static void scanExistingJars() { // Scan existing jars for missing directory entries String[] paths = System.getProperty("java.class.path").split(File.pathSeparator); for (String path : paths) { INSTANCE.classLoader.scanJar(Paths.get(path)); } } } jpype-1.3.0/native/java/org/jpype/JPypeKeywords.java000066400000000000000000000031471405671516700224320ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype; import java.util.Arrays; import java.util.HashSet; import java.util.Set; /** * * @author nelson85 */ public class JPypeKeywords { final public static Set keywords = new HashSet<>(); public static void setKeywords(String[] s) { keywords.addAll(Arrays.asList(s)); } public static String wrap(String name) { if (keywords.contains(name)) return name + "_"; return name; } public static String unwrap(String name) { if (!name.endsWith("_")) return name; String name2 = name.substring(0, name.length() - 1); if (keywords.contains(name2)) return name2;; return name; } static String safepkg(String s) { if (!s.contains("_")) return s; String[] parts = s.split("\\."); for (int i = 0; i < parts.length; ++i) parts[i] = unwrap(parts[i]); return String.join(".", parts); } } jpype-1.3.0/native/java/org/jpype/JPypeSignal.java000066400000000000000000000043461405671516700220420ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * Java wants to make this action nearly impossible. * * Thus the have warnings against it that cannot be disabled. So we will skin * this cat another way. */ public class JPypeSignal { static Thread main; static void installHandlers() { try { Class Signal = Class.forName("sun.misc.Signal"); Class SignalHandler = Class.forName("sun.misc.SignalHandler"); main = Thread.currentThread(); Method method = Signal.getMethod("handle", Signal, SignalHandler); Object handler = Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[] { SignalHandler }, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { main.interrupt(); interruptPy(); return null; } }); Object intr = Signal.getDeclaredConstructor(String.class).newInstance("INT"); method.invoke(null, intr, handler); } catch (InvocationTargetException | IllegalArgumentException | IllegalAccessException | InstantiationException | ClassNotFoundException | NoSuchMethodException | SecurityException ex) { // If we don't get the signal handler run without it. (ANDROID) } } native static void interruptPy(); native static void acknowledgePy(); } jpype-1.3.0/native/java/org/jpype/JPypeUtilities.java000066400000000000000000000006061405671516700225730ustar00rootroot00000000000000package org.jpype; import java.net.URISyntaxException; import java.nio.file.Path; import java.nio.file.Paths; public class JPypeUtilities { public static Path getJarPath(Class c) { try { return Paths.get(c.getProtectionDomain().getCodeSource().getLocation() .toURI()).getParent(); } catch (URISyntaxException ex) { return null; } } } jpype-1.3.0/native/java/org/jpype/PyExceptionProxy.java000066400000000000000000000003351405671516700231600ustar00rootroot00000000000000package org.jpype; /** * * @author nelson85 */ public class PyExceptionProxy extends RuntimeException { long cls; long value; public PyExceptionProxy(long l0, long l1) { cls = l0; value = l1; } } jpype-1.3.0/native/java/org/jpype/classloader/000077500000000000000000000000001405671516700212775ustar00rootroot00000000000000jpype-1.3.0/native/java/org/jpype/classloader/DynamicClassLoader.java000066400000000000000000000147751405671516700256610ustar00rootroot00000000000000package org.jpype.classloader; import java.io.ByteArrayOutputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; import java.net.URLClassLoader; import java.net.URLConnection; import java.nio.file.FileSystems; import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.PathMatcher; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.JarFile; public class DynamicClassLoader extends ClassLoader { List loaders = new LinkedList<>(); HashMap> map = new HashMap<>(); public DynamicClassLoader(ClassLoader parent) { super(parent); } public int getCode() { return loaders.hashCode(); } /** * Add a set of jars to the classpath. * * @param root * @param glob * @throws IOException */ public void addFiles(Path root, String glob) throws IOException { final PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher(glob); List urls = new LinkedList<>(); Files.walkFileTree(root, new SimpleFileVisitor() { @Override public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException { if (pathMatcher.matches(root.relativize(path))) { URL url = path.toUri().toURL(); urls.add(url); } return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { return FileVisitResult.CONTINUE; } }); loaders.add(new URLClassLoader(urls.toArray(new URL[urls.size()]))); } public void addFile(Path path) throws FileNotFoundException { try { if (!Files.exists(path)) throw new FileNotFoundException(path.toString()); URL[] urls = new URL[] { path.toUri().toURL() }; loaders.add(new URLClassLoader(urls)); // Scan the file for directory entries this.scanJar(path); } catch (MalformedURLException ex) { // This should never happen throw new RuntimeException(ex); } } /** * Loads a class from the class loader. * * @param name is the name of the class with java class notation (using dots). * @return the class * @throws ClassNotFoundException was not found by the class loader. * @throws ClassFormatError if the class byte code was invalid. */ @Override public Class findClass(String name) throws ClassNotFoundException, ClassFormatError { String aname = name.replace('.', '/') + ".class"; URL url = this.getResource(aname); if (url == null) throw new ClassNotFoundException(name); try { URLConnection connection = url.openConnection(); try ( InputStream is = connection.getInputStream()) { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); int bytes; byte[] d = new byte[1024]; while ((bytes = is.read(d, 0, d.length)) != -1) { buffer.write(d, 0, bytes); } buffer.flush(); byte[] data = buffer.toByteArray(); return defineClass(name, data, 0, data.length); } } catch (IOException ex) { } throw new ClassNotFoundException(name); } @Override public URL getResource(String name) { URL url = this.getParent().getResource(name); if (url != null) return url; for (ClassLoader cl : this.loaders) { url = cl.getResource(name); if (url != null) return url; } // Both with and without / should generate the same result if (name.endsWith("/")) name = name.substring(0, name.length() - 1); if (map.containsKey(name)) return map.get(name).get(0); return null; } @Override public Enumeration getResources(String name) throws IOException { ArrayList out = new ArrayList<>(); Enumeration urls = getParent().getResources(name); out.addAll(Collections.list(urls)); for (URLClassLoader cl : this.loaders) { urls = cl.findResources(name); out.addAll(Collections.list(urls)); } // Both with and without / should generate the same result if (name.endsWith("/")) name = name.substring(0, name.length() - 1); if (map.containsKey(name)) out.addAll(map.get(name)); return Collections.enumeration(out); } public void addResource(String name, URL url) { if (!this.map.containsKey(name)) this.map.put(name, new ArrayList<>()); this.map.get(name).add(url); } /** * Recreate missing directory entries for Jars that lack indexing. * * Some jar files are missing the directory entries that prevents use from * properly importing their contents. This procedure scans a jar file when * loaded to build missing directories. * * @param p1 */ public void scanJar(Path p1) { if (!Files.exists(p1)) return; if (Files.isDirectory(p1)) return; try ( JarFile jf = new JarFile(p1.toFile())) { Enumeration entries = jf.entries(); URI abs = p1.toAbsolutePath().toUri(); Set urls = new java.util.HashSet(); while (entries.hasMoreElements()) { JarEntry next = entries.nextElement(); String name = next.getName(); // Skip over META-INF if (name.startsWith("META-INF/")) continue; if (next.isDirectory()) { // If we find a directory entry then the jar has directories already return; } // Split on each separator in the name int i = 0; while (true) { i = name.indexOf("/", i); if (i == -1) break; String name2 = name.substring(0, i); i++; // Already have an entry no problem if (urls.contains(name2)) continue; // Add a new entry for the missing directory String jar = "jar:" + abs + "!/" + name2 + "/"; urls.add(name2); this.addResource(name2, new URL(jar)); } } } catch (IOException ex) { // Anything goes wrong skip it } } } jpype-1.3.0/native/java/org/jpype/classloader/JPypeClassLoader.java000066400000000000000000000077211405671516700253150ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype.classloader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.TreeMap; import java.util.jar.JarEntry; import java.util.jar.JarInputStream; /** * Specialized class loader for JPype resources. *

* Loader to convert the internally stored resources into java classes. This * prevents class load order problems when there are class dependencies. *

*/ public class JPypeClassLoader extends ClassLoader { static private JPypeClassLoader instance; private TreeMap map = new TreeMap<>(); /** * Get the class loader. * * @return the singleton class loader. */ public static JPypeClassLoader getInstance() { if (instance == null) { JPypeClassLoader.instance = new JPypeClassLoader(getSystemClassLoader()); } return instance; } private JPypeClassLoader(ClassLoader parent) { super(parent); } /** * Add a class to the class loader. *

* This can be called from within python to add a class to the Java JVM. * * @param name is the name of the class. * @param code is the byte code. */ public void importClass(String name, byte[] code) { map.put(name, code); } /** * Import a jar from memory into the class loader. *

* Does not handle unknown jar entry lengths. * * @param bytes */ public void importJar(byte[] bytes) { try (JarInputStream is = new JarInputStream(new ByteArrayInputStream(bytes))) { while (true) { JarEntry nextEntry = is.getNextJarEntry(); if (nextEntry == null) break; // Skip directories and other non-class resources long size = nextEntry.getSize(); if (size == 0) continue; ByteArrayOutputStream baos = new ByteArrayOutputStream(); int q; while ((q = is.read()) != -1) baos.write(q); byte[] data = baos.toByteArray(); // Store all classes we find String name = nextEntry.getName(); importClass(name, data); } } catch (IOException ex) { throw new RuntimeException(ex); } } /** * Loads a class from the class loader. * * @param name is the name of the class with java class notation (using dots). * @return the class * @throws ClassNotFoundException was not found by the class loader. * @throws ClassFormatError if the class byte code was invalid. */ @Override public Class findClass(String name) throws ClassNotFoundException, ClassFormatError { String mname = name.replace('.', '/') + ".class"; byte[] data = map.get(mname); if (data == null) { // Call the default implementation, throws ClassNotFoundException return super.findClass(name); } Class cls = defineClass(name, data, 0, data.length); if (cls == null) throw new ClassFormatError("Class load was null"); return cls; } /** * Overload for thunk resources. * * @param s * @return */ @Override public InputStream getResourceAsStream(String s) { if (this.map.containsKey(s)) { return new ByteArrayInputStream(this.map.get(s)); } return super.getResourceAsStream(s); } } jpype-1.3.0/native/java/org/jpype/html/000077500000000000000000000000001405671516700177475ustar00rootroot00000000000000jpype-1.3.0/native/java/org/jpype/html/AttrGrammar.java000066400000000000000000000127061405671516700230410ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype.html; import org.jpype.html.Parser.Entity; import org.jpype.html.Parser.Rule; import org.w3c.dom.Attr; public class AttrGrammar implements Parser.Grammar { static final AttrGrammar INSTANCE = new AttrGrammar(); private AttrGrammar() { } @Override public void start(Parser p) { p.state = State.FREE; ((AttrParser) p).attrs.clear(); } @Override public Object end(Parser p) { return ((AttrParser) p).attrs; } // enum Token implements Parser.Token { TEXT, QUOTE("\""), SQUOTE("'"), EQ("="), WHITESPACE(" "); byte value; String text; Token() { } Token(String s) { text = s; if (s.length() == 1) value = (byte) s.charAt(0); } @Override final public boolean matches(byte b) { if (value == ' ') return Character.isWhitespace(b); if (value == 0) return true; return b == value; } @Override public boolean runs() { return this == Token.TEXT; } @Override public String toString() { if (text != null) return text; return "TEXT"; } } final static Token[] freeTokens = tokens( Token.QUOTE, Token.SQUOTE, Token.EQ, Token.WHITESPACE, Token.TEXT); final static Token[] qtTokens = tokens( Token.QUOTE, Token.TEXT); final static Token[] sqtTokens = tokens( Token.SQUOTE, Token.TEXT); final static Rule ignoreWS = new IgnoreWSRule(); final static Rule quoteRule = new QuoteRule(); final static Rule endRule = new EndQuoteRule(); final static Rule attrRule = new AttrRule(); final static Rule boolRule = new BooleanRule(); final static Rule[] freeRules = rules(attrRule, boolRule, ignoreWS, quoteRule); final static Rule[] qtRules = rules(endRule); static Token[] tokens(Token... t) { return t; } static Rule[] rules(Rule... t) { return t; } // // enum State implements Parser.State { FREE(freeTokens, freeRules), IN_QUOTE(qtTokens, qtRules), IN_SQUOTE(sqtTokens, qtRules); Token[] tokens; Rule[] rules; State(Token[] tokens, Rule[] rules) { this.tokens = tokens; this.rules = rules; } @Override public Token[] getTokens() { return this.tokens; } @Override public Rule[] getRules() { return this.rules; } } // // static class IgnoreWSRule implements Rule { @Override public boolean apply(Parser parser, Entity entity) { if (entity.token != Token.WHITESPACE) return false; parser.stack.removeLast(); return true; } } static class QuoteRule implements Rule { @Override public boolean apply(Parser parser, Entity entity) { if (entity.token == Token.QUOTE) { parser.state = State.IN_QUOTE; parser.stack.removeLast(); return true; } if (entity.token == Token.SQUOTE) { parser.state = State.IN_SQUOTE; parser.stack.removeLast(); return true; } return false; } } static class EndQuoteRule implements Rule { @Override public boolean apply(Parser parser, Entity entity) { if (State.IN_QUOTE == parser.state && entity.token == Token.QUOTE) { parser.state = State.FREE; parser.stack.removeLast(); return true; } if (State.IN_SQUOTE == parser.state && entity.token == Token.SQUOTE) { parser.state = State.FREE; parser.stack.removeLast(); return true; } return false; } } static class AttrRule extends Parser.MatchRule { AttrRule() { super(Token.TEXT, Token.EQ, Token.TEXT); } @Override public void execute(Parser parser) { Entity e2 = (Entity) parser.stack.removeLast(); Entity e1 = (Entity) parser.stack.removeLast(); Entity e0 = (Entity) parser.stack.removeLast(); AttrParser aparser = (AttrParser) parser; Attr attr = aparser.doc.createAttribute((String) e0.value); attr.setNodeValue((String) e2.value); aparser.attrs.add(attr); } } static class BooleanRule extends Parser.MatchRule { BooleanRule() { super(Token.TEXT, Token.TEXT); } @Override public void execute(Parser parser) { Entity e2 = (Entity) parser.stack.removeLast(); Entity e1 = (Entity) parser.stack.removeLast(); AttrParser aparser = (AttrParser) parser; Attr attr = aparser.doc.createAttribute((String) e1.value); attr.setNodeValue((String) e1.value); aparser.attrs.add(attr); parser.stack.add(e2); } } // } jpype-1.3.0/native/java/org/jpype/html/AttrParser.java000066400000000000000000000020761405671516700227060ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype.html; import java.util.ArrayList; import java.util.List; import org.w3c.dom.Attr; import org.w3c.dom.Document; public class AttrParser extends Parser> { final Document doc; final List attrs = new ArrayList<>(); public AttrParser(Document doc) { super(AttrGrammar.INSTANCE); this.doc = doc; } } jpype-1.3.0/native/java/org/jpype/html/Html.java000066400000000000000000000127661405671516700215320ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype.html; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import org.jpype.JPypeContext; import org.w3c.dom.Attr; import org.w3c.dom.Document; public class Html { public final static HashSet VOID_ELEMENTS = new HashSet<>(); public final static HashSet OPTIONAL_ELEMENTS = new HashSet<>(); public final static HashSet OPTIONAL_CLOSE = new HashSet<>(); static { VOID_ELEMENTS.addAll(Arrays.asList( "area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr")); OPTIONAL_ELEMENTS.addAll(Arrays.asList("html", "head", "body", "p", "dt", "dd", "li", "option", "thead", "th", "tbody", "tr", "td", "tfoot", "colgroup")); OPTIONAL_CLOSE.addAll(Arrays.asList("li:li", "dt:dd", "p:address", "p:article", "p:aside", "p:blockquote", "p:details", "p:div", "p:dl", "p:fieldset", "p:figcaption", "p:figure", "p:footer", "p:form", "p:h1", "p:h2", "p:h3", "p:h4", "p:h5", "p:h6", "p:header", "p:hgroup", "p:hr", "p:main", "p:menu", "p:nav", "p:ol", "p:p", "p:pre", "p:section", "p:table", "p:ul", "dd:dt", "dd:dd", "dt:dt", "dt:dd", "rt:rt", "rt:rp", "rp:rt", "rp:rp", "optgroup:optgroup", "option:option", "option:optiongroup", "thread:tbody", "thread:tfoot", "tbody:tfoot", "tbody:tbody", "tr:tr", "td:td", "td:th", "th:td", "p:li")); } public static Parser newParser() { return new HtmlParser(); } public static List parseAttributes(Document doc, String str) { AttrParser p = new AttrParser(doc); p.parse(str); return p.attrs; } // public static Map ENTITIES = new HashMap<>(); static { try (InputStream is = JPypeContext.getInstance().getClass().getClassLoader() .getResourceAsStream("org/jpype/html/entities.txt"); InputStreamReader isr = new InputStreamReader(is); BufferedReader rd = new BufferedReader(isr)) { while (true) { String line = rd.readLine(); if (line == null) break; if (line.startsWith("#")) continue; String[] parts = line.split("\\s+"); ENTITIES.put(parts[0], Integer.parseInt(parts[1])); } } catch (IOException ex) { throw new RuntimeException(ex); } } public static String decode(String s) { if (!s.contains("&")) return s; int dead = 0; byte[] b = s.getBytes(StandardCharsets.UTF_8); for (int i = 0; i < b.length; ++i) { if (b[i] != '&') continue; int i1 = i; int i2 = i + 1; if (i2 == b.length) break; if (b[i2] == '#') { // Try to be robust when there is no ; for (i = i2 + 1; i < b.length; ++i) { if (!Character.isDigit(b[i])) break; } } else { for (i = i2; i < b.length; ++i) { if (b[i] == ';') break; } } int i3 = i; int c = 0; if (b[i2] == '#') { i2++; try { c = Integer.parseInt(new String(b, i2, i3 - i2, StandardCharsets.UTF_8)); } catch (NumberFormatException ex) { } } else { String e = new String(b, i2, i3 - i2, StandardCharsets.UTF_8); Integer c2 = ENTITIES.get(e); if (c2 == null) throw new RuntimeException("Bad entity " + e); c = c2; } // Substitute if (c < 128) { b[i1++] = (byte) c; } else if (c < 0x0800) { b[i1++] = (byte) (0xc0 + ((c >> 6) & 0x1f)); if (i1 < b.length) // lgtm [java/constant-comparison] b[i1++] = (byte) (0x80 + (c & 0x3f)); // lgtm [java/index-out-of-bounds] } else { b[i1++] = (byte) (0xe0 + ((c >> 12) & 0x0f)); if (i1 < b.length) // lgtm [java/constant-comparison] b[i1++] = (byte) (0x80 + ((c >> 6) & 0x3f)); // lgtm [java/index-out-of-bounds] if (i1 < b.length) b[i1++] = (byte) (0x80 + (c & 0x3f)); } if (i3 < b.length && b[i3] == ';') i3++; dead += i3 - i1; for (; i1 < i3; ++i1) b[i1] = 0; i = i3; } int j = 0; byte[] b2 = new byte[b.length - dead]; for (int i = 0; i < b.length; ++i) { if (b[i] != 0) b2[j++] = b[i]; } return new String(b2, StandardCharsets.UTF_8); } // } jpype-1.3.0/native/java/org/jpype/html/HtmlGrammar.java000066400000000000000000000365571405671516700230450ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype.html; import java.util.LinkedList; import org.jpype.html.Parser.Entity; import org.jpype.html.Parser.Rule; public class HtmlGrammar implements Parser.Grammar { final static HtmlGrammar INSTANCE = new HtmlGrammar(); private HtmlGrammar() { } @Override public void start(Parser p) { p.state = State.FREE; ((HtmlParser) p).handler.startDocument(); } @Override public Object end(Parser p) { ((HtmlParser) p).handler.endDocument(); return ((HtmlParser) p).handler.getResult(); } // BeginElement does < parser) { if (parser.stack.isEmpty()) return; Entity last = parser.stack.removeLast(); StringBuilder s = new StringBuilder(); for (Entity e : parser.stack) { s.append(e.toString()); } ((HtmlParser) parser).handler.text(s.toString()); parser.stack.clear(); parser.stack.add(last); } // enum State implements Parser.State { FREE(freeTokens, freeRules), ELEMENT(elementTokens, elementRules), DIRECTIVE(directiveTokens, directiveRules), CDATA(cdataTokens, cdataRules), COMMENT(commentTokens, commentRules); Token[] tokens; Rule[] rules; State(Token[] tokens, Rule[] rules) { this.tokens = tokens; this.rules = rules; } @Override public Token[] getTokens() { return this.tokens; } @Override public Rule[] getRules() { return this.rules; } } // // enum Token implements Parser.Token { TEXT, BANG("!"), DASH("-"), LT("<"), GT(">"), SLASH("/"), AMP("&"), SEMI(";"), LSB("["), RSB("]"), CLOSE(" // final static Rule escaped = new Escaped(); final static Rule slash = new Cleanup(); final static Rule mergeText = new MergeText(); final static Rule beginElement = new BeginElement(); final static Rule startElement = new StartElement(); final static Rule completeElement = new CompleteElement(); final static Rule endElement = new EndElement(); final static Rule quote = new StartQuote(); final static Token[] freeTokens = tokens( Token.LT, Token.AMP, Token.SEMI, Token.TEXT); final static Token[] elementTokens = tokens( Token.BANG, Token.AMP, Token.LT, Token.SEMI, Token.SLASH, Token.GT, Token.QUOTE, Token.SQUOTE, Token.TEXT); final static Token[] directiveTokens = tokens( Token.DASH, Token.LSB, Token.RSB, Token.LT, Token.GT, Token.QUOTE, Token.SQUOTE, Token.TEXT); final static Token[] cdataTokens = tokens( Token.LSB, Token.RSB, Token.GT, Token.TEXT); final static Token[] commentTokens = tokens( Token.DASH, Token.GT, Token.TEXT); final static Token[] quoteTokens = tokens( Token.QUOTE, Token.TEXT); final static Token[] squoteTokens = tokens( Token.SQUOTE, Token.TEXT); final static Rule[] freeRules = rules( beginElement, escaped, mergeText); final static Rule[] elementRules = rules( mergeText, quote, startElement, endElement, completeElement, escaped, slash); final static Rule[] directiveRules = rules(quote, new EndDirective(), mergeText); final static Rule[] cdataRules = rules( new EndCData()); final static Rule[] commentRules = rules( new EndComment(), new StartComment()); private static Rule[] rules(Rule... t) { return t; } private static Token[] tokens(Token... t) { return t; } // // private static class Cleanup implements Rule { @Override public boolean apply(Parser parser, Entity entity) { if (entity.token == Token.SLASH) { parser.lookahead = this::next; return false; } if (entity.token == Token.GT && parser.stack.size() > 4) { // This it to help debug a rare problem for (Entity e : parser.stack) { System.out.print(e.token); System.out.print("("); System.out.print(e.value); System.out.print(") "); } System.out.println(); throw new RuntimeException("Need cleanup"); } return false; } private boolean next(Parser parser, Entity entity) { if (entity.token != Token.GT) { parser.stack.removeLast(); parser.stack.removeLast(); // parser.stack.getLast().token = Token.TEXT; entity.value = "/" + entity.value; parser.stack.add(entity); } return false; } } private static class Escaped extends Parser.MatchRule { public Escaped() { super(Token.AMP, Token.TEXT, Token.SEMI); } @Override public void execute(Parser parser) { LinkedList stack = parser.stack; Entity e2 = stack.removeLast(); Entity e1 = stack.removeLast(); // Currently we do not verify the text contents Entity e0 = stack.getLast(); promote(e0).append(e1.toString()).append(e2.toString()); } } static class MergeText extends Parser.MatchRule { public MergeText() { super(Token.TEXT, Token.TEXT); } @Override public void execute(Parser parser) { LinkedList stack = parser.stack; Entity t2 = stack.removeLast(); Entity t1 = stack.getLast(); promote(t1).append(t2.toString()); } } // // static class BeginElement implements Rule { @Override public boolean apply(Parser parser, Entity entity) { if (entity.token != Token.LT) return false; getGrammar(parser).flushText(parser); parser.state = State.ELEMENT; parser.lookahead = this::next; return true; } public boolean next(Parser parser, Parser.Entity entity) { if (entity.token == Token.SLASH) { parser.stack.removeLast(); parser.stack.getLast().token = Token.CLOSE; return true; } if (entity.token == Token.BANG) { parser.stack.removeLast(); Entity last = parser.stack.getLast(); last.token = Token.DECL_DIRECTIVE; parser.lookahead = new Directive(); parser.state = State.DIRECTIVE; return true; } return false; } } static class StartElement extends Parser.MatchRule { StartElement() { super(Token.LT, Token.TEXT, Token.GT); } @Override public void execute(Parser parser) { LinkedList stack = parser.stack; stack.removeLast(); Entity e1 = stack.removeLast(); stack.removeLast(); String content = e1.value.toString(); getGrammar(parser).flushText(parser); String[] parts = content.split("\\s+", 2); if (parts.length == 1) getHandler(parser).startElement(content, null); else getHandler(parser).startElement(parts[0], parts[1]); parser.state = State.FREE; } } static class CompleteElement extends Parser.MatchRule { CompleteElement() { super(Token.LT, Token.TEXT, Token.SLASH, Token.GT); } @Override public void execute(Parser parser) { LinkedList stack = parser.stack; stack.removeLast(); // > stack.removeLast(); // / Entity e1 = stack.removeLast(); stack.removeLast(); // < String content = e1.value.toString(); stack.clear(); int i = content.indexOf(" "); if (i == -1) { getHandler(parser).startElement(content, null); getHandler(parser).endElement(content); } else { String name = content.substring(0, i); String attr = content.substring(i).trim(); getHandler(parser).startElement(name, attr); getHandler(parser).endElement(name); } parser.state = State.FREE; } } static class EndElement extends Parser.MatchRule { EndElement() { super(Token.CLOSE, Token.TEXT, Token.GT); } @Override public void execute(Parser parser) { LinkedList stack = parser.stack; Entity e2 = stack.removeLast(); Entity e1 = stack.removeLast(); Entity e0 = stack.removeLast(); String content = e1.value.toString(); getGrammar(parser).flushText(parser); getHandler(parser).endElement(content); parser.state = State.FREE; } } static class EndDirective extends Parser.MatchRule { EndDirective() { super(Token.DECL_DIRECTIVE, Token.TEXT, Token.GT); } @Override public void execute(Parser parser) { LinkedList stack = parser.stack; Entity e2 = stack.removeLast(); Entity e1 = stack.removeLast(); Entity e0 = stack.removeLast(); String content = e1.value.toString(); getGrammar(parser).flushText(parser); getHandler(parser).directive(content); parser.state = State.FREE; } } // // // This is a look ahead rule static class Directive implements Rule { @Override public boolean apply(Parser parser, Entity entity) { if (entity.token == Token.LSB) { parser.lookahead = new CData(); return true; } if (entity.token == Token.DASH) { parser.lookahead = new Comment(); return true; } return false; } } static class CData implements Rule { @Override public boolean apply(Parser parser, Entity entity) { if (entity.token != Token.TEXT) parser.error("Expected CDATA"); parser.lookahead = this::next; return true; } public boolean next(Parser parser, Parser.Entity entity) { if (entity.token != Token.LSB) parser.error("Expected ["); parser.stack.clear(); parser.state = State.CDATA; return true; } } static class EndCData extends Parser.MatchRule { public EndCData() { super(Token.RSB, Token.RSB, Token.GT); } @Override public void execute(Parser parser) { LinkedList stack = parser.stack; stack.removeLast(); // > stack.removeLast(); // ] stack.removeLast(); // ] Entity first = stack.removeFirst(); StringBuilder sb = promote(first); for (Entity e : stack) { sb.append(e.toString()); } stack.clear(); ((HtmlParser) parser).handler.cdata(sb.toString()); parser.state = State.FREE; } } static class Comment implements Rule { @Override public boolean apply(Parser parser, Entity entity) { if (entity.token != Token.DASH) parser.error("Expected -"); parser.lookahead = this::next; parser.stack.clear(); parser.state = State.COMMENT; return true; } public boolean next(Parser parser, Parser.Entity entity) { if (entity.token == Token.DASH) parser.error("Bad comment(-)"); if (entity.token == Token.GT) parser.error("Bad comment(>)"); return false; } } static class StartComment extends Parser.MatchRule { public StartComment() { super(Token.LT, Token.BANG, Token.DASH, Token.DASH); } @Override public void execute(Parser parser) { parser.lookahead = this::next; } public boolean next(Parser parser, Parser.Entity entity) { if (entity.token == Token.GT) return false; parser.error("Comment contains "); } private void writeCData(CDATASection cData) throws IOException { writer.write(""); } private void writeText(Text text) throws IOException { writer.write(text.getData()); } @Override public void close() throws IOException { writer.close(); } } jpype-1.3.0/native/java/org/jpype/html/Parser.java000066400000000000000000000145721405671516700220570ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype.html; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; import java.util.LinkedList; import java.util.ListIterator; /** * Generic document parser. * * @param */ public class Parser { final Grammar grammar; public State state = null; public Token last = null; public Rule lookahead = null; public LinkedList stack = new LinkedList<>(); Parser(Grammar grammar) { this.grammar = grammar; } public T parse(InputStream is) { ByteBuffer incoming = ByteBuffer.allocate(1024); ByteBuffer outgoing = ByteBuffer.allocate(1024); ReadableByteChannel channel = Channels.newChannel(is); stack.clear(); grammar.start(this); try { while (true) { incoming.position(0); int rc = channel.read(incoming); if (rc < 0) break; int p = incoming.position(); incoming.rewind(); process(incoming, outgoing, rc); } flushTokens(outgoing); } catch (IOException ex) { throw new RuntimeException(ex); } return (T) grammar.end(this); } public T parse(String str) { byte[] b = str.getBytes(); ByteBuffer incoming = ByteBuffer.wrap(b); ByteBuffer outgoing = ByteBuffer.allocate(1024); stack.clear(); grammar.start(this); process(incoming, outgoing, b.length); flushTokens(outgoing); return (T) grammar.end(this); } private void process(ByteBuffer incoming, ByteBuffer outgoing, int rc) { while (incoming.position() < rc) { byte b = incoming.get(); Token match = null; for (Token t : state.getTokens()) { if (t.matches(b)) { match = t; break; } } if (match == null) this.error("Unable to parse " + (char) b); else if (match.runs()) { if (last != match) flushTokens(outgoing); if (!outgoing.hasRemaining()) flushTokens(outgoing); outgoing.put(b); } else { if (outgoing.position() > 0) flushTokens(outgoing); processToken(match, null); } last = match; } } /** * Send all the queue up text to a token. */ private void flushTokens(ByteBuffer outgoing) { if (outgoing.position() == 0) return; processToken(last, new String(outgoing.array(), 0, outgoing.position())); outgoing.rewind(); } /** * Process a token. * * This will add it to the stack and then match the stack with the nearest * rule. * * @param token * @param value */ protected void processToken(Token token, String value) { if (token == null) return; Entity entity = add(token, value); // Take the next lookahead Rule rule1 = this.lookahead; this.lookahead = null; if (rule1 != null) { // System.out.println(" FORWARD " + rule1); if (rule1.apply(this, entity)) { return; } } // If not handled then proceed to rules. boolean done = false; while (!done && !stack.isEmpty()) { done = true; for (Rule rule : state.getRules()) { // System.out.println(" RULE " + rule); if (rule.apply(this, stack.getLast())) { done = false; break; } } } } /** * Add a token to the token stack * * @param token * @param object * @return */ public Entity add(Token token, String object) { Entity entity = new Entity(token, object); this.stack.add(entity); return entity; } public void error(String bad_token) { throw new RuntimeException("bad_token"); } public interface State { Token[] getTokens(); Rule[] getRules(); } public interface Token { int ordinal(); public boolean matches(byte b); public boolean runs(); } public interface Rule { boolean apply(Parser parser, Entity entity); } public interface Grammar { /** * Should set the initial state. * * @param p */ public void start(Parser p); /** * Should check the state of the stack, fail if bad, or return the final * object if good. * * @param p * @return */ public Object end(Parser p); } /** * Token or text. */ public static class Entity { public Token token; public Object value; private Entity(Token token) { this.token = token; } private Entity(Token token, String value) { this.token = token; this.value = value; } @Override public String toString() { if (value == null) return token.toString(); return value.toString(); } } // /** * Generic matcher for multiple tokens on the stack. */ abstract static class MatchRule implements Rule { Token[] pattern; MatchRule(Token... tokens) { this.pattern = tokens; } @Override public boolean apply(Parser parser, Entity entity) { LinkedList stack = parser.stack; int n = stack.size(); if (n < pattern.length) return false; ListIterator iter = stack.listIterator(stack.size()); for (int i = 0; i < pattern.length; ++i) { if (!iter.hasPrevious()) return false; Entity next = iter.previous(); if (next.token != pattern[pattern.length - i - 1]) { return false; } } execute(parser); return true; } abstract public void execute(Parser parser); } // } jpype-1.3.0/native/java/org/jpype/html/entities.txt000066400000000000000000000070401405671516700223350ustar00rootroot00000000000000# Portions © International Organization for Standardization 1986: # Permission to copy in any form is granted for use with # conforming SGML systems and applications as defined in # ISO 8879, provided this notice is included in all copies. nbsp 160 iexcl 161 cent 162 pound 163 curren 164 yen 165 brvbar 166 sect 167 uml 168 copy 169 ordf 170 laquo 171 not 172 shy 173 reg 174 macr 175 deg 176 plusmn 177 sup2 178 sup3 179 acute 180 micro 181 para 182 middot 183 cedil 184 sup1 185 ordm 186 raquo 187 frac14 188 frac12 189 frac34 190 iquest 191 Agrave 192 Aacute 193 Acirc 194 Atilde 195 Auml 196 Aring 197 AElig 198 Ccedil 199 Egrave 200 Eacute 201 Ecirc 202 Euml 203 Igrave 204 Iacute 205 Icirc 206 Iuml 207 ETH 208 Ntilde 209 Ograve 210 Oacute 211 Ocirc 212 Otilde 213 Ouml 214 times 215 Oslash 216 Ugrave 217 Uacute 218 Ucirc 219 Uuml 220 Yacute 221 THORN 222 szlig 223 agrave 224 aacute 225 acirc 226 atilde 227 auml 228 aring 229 aelig 230 ccedil 231 egrave 232 eacute 233 ecirc 234 euml 235 igrave 236 iacute 237 icirc 238 iuml 239 eth 240 ntilde 241 ograve 242 oacute 243 ocirc 244 otilde 245 ouml 246 divide 247 oslash 248 ugrave 249 uacute 250 ucirc 251 uuml 252 yacute 253 thorn 254 yuml 255 fnof 402 Alpha 913 Beta 914 Gamma 915 Delta 916 Epsilon 917 Zeta 918 Eta 919 Theta 920 Iota 921 Kappa 922 Lambda 923 Mu 924 Nu 925 Xi 926 Omicron 927 Pi 928 Rho 929 Sigma 931 Tau 932 Upsilon 933 Phi 934 Chi 935 Psi 936 Omega 937 alpha 945 beta 946 gamma 947 delta 948 epsilon 949 zeta 950 eta 951 theta 952 iota 953 kappa 954 lambda 955 mu 956 nu 957 xi 958 omicron 959 pi 960 rho 961 sigmaf 962 sigma 963 tau 964 upsilon 965 phi 966 chi 967 psi 968 omega 969 thetasym 977 upsih 978 piv 982 bull 8226 hellip 8230 prime 8242 Prime 8243 oline 8254 frasl 8260 weierp 8472 image 8465 real 8476 trade 8482 alefsym 8501 larr 8592 uarr 8593 rarr 8594 darr 8595 harr 8596 crarr 8629 lArr 8656 uArr 8657 rArr 8658 dArr 8659 hArr 8660 forall 8704 part 8706 exist 8707 empty 8709 nabla 8711 isin 8712 notin 8713 ni 8715 prod 8719 sum 8721 minus 8722 lowast 8727 radic 8730 prop 8733 infin 8734 ang 8736 and 8743 or 8744 cap 8745 cup 8746 int 8747 there4 8756 sim 8764 cong 8773 asymp 8776 ne 8800 equiv 8801 le 8804 ge 8805 sub 8834 sup 8835 nsub 8836 sube 8838 supe 8839 oplus 8853 otimes 8855 perp 8869 sdot 8901 lceil 8968 rceil 8969 lfloor 8970 rfloor 8971 lang 9001 rang 9002 loz 9674 spades 9824 clubs 9827 hearts 9829 diams 9830 quot 34 amp 38 lt 60 gt 62 OElig 338 oelig 339 Scaron 352 scaron 353 Yuml 376 circ 710 tilde 732 ensp 8194 emsp 8195 thinsp 8201 zwnj 8204 zwj 8205 lrm 8206 rlm 8207 ndash 8211 mdash 8212 lsquo 8216 rsquo 8217 sbquo 8218 ldquo 8220 rdquo 8221 bdquo 8222 dagger 8224 Dagger 8225 permil 8240 lsaquo 8249 rsaquo 8250 euro 8364jpype-1.3.0/native/java/org/jpype/javadoc/000077500000000000000000000000001405671516700204125ustar00rootroot00000000000000jpype-1.3.0/native/java/org/jpype/javadoc/DomUtilities.java000066400000000000000000000146231405671516700236760ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype.javadoc; /** * The usual set of method required to work on DOM. * * DOM leaves a lot of basic stuff incomplete. */ import java.util.function.BiConsumer; import java.util.function.Consumer; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.Text; public class DomUtilities { /** * Traverse all children in depth first order applying an operation. * * This is hardened against some level of DOM changes. * * @param node * @param operator * @param type */ public static void traverseDFS(Node node, Consumer operator, short type) { Node child = node.getFirstChild(); while (child != null) { // Get a referent to what we are processing next in case the tree changes. Node next = child.getNextSibling(); // Apply transforms to children first if (child.getNodeType() == Node.ELEMENT_NODE) traverseDFS(child, operator, type); // Then process the outer element if (child.getNodeType() == type) operator.accept(child); // Proceed child = next; } } /** * Traverse the children of a node applying an operation. * * This is hardened against some level of DOM changes. * * @param node * @param operator * @param type */ public static void traverseChildren(Node node, Consumer operator, short type) { Node child = node.getFirstChild(); while (child != null) { // Get the next node to process in case this one is changed or removed. Node next = child.getNextSibling(); if (child.getNodeType() == type) operator.accept(child); // Proceed. child = next; } } /** * Traverse all children in depth first order applying an operation. * * This is hardened against some level of DOM changes. * * @param node * @param operator * @param type */ public static void traverseDFS(Node node, BiConsumer operator, short type, T data) { Node child = node.getFirstChild(); while (child != null) { // Get a referent to what we are processing next in case the tree changes. Node next = child.getNextSibling(); // Apply transforms to children first if (child.getNodeType() == Node.ELEMENT_NODE) traverseDFS(child, operator, type, data); // Then process the outer element if (child.getNodeType() == type) operator.accept(child, data); // Proceed child = next; } } /** * Traverse the children of a node applying an operation. * * This is hardened against some level of DOM changes. * * @param node * @param operator * @param type */ public static void traverseChildren(Node node, BiConsumer operator, short type, T data) { Node child = node.getFirstChild(); while (child != null) { // Get the next node to process in case this one is changed or removed. Node next = child.getNextSibling(); if (child.getNodeType() == type) operator.accept(child, data); // Proceed. child = next; } } /** * Remove all attributes from a node. * * @param node */ public static void clearAttributes(Node node) { while (node.getAttributes().getLength() > 0) { Node att = node.getAttributes().item(0); node.getAttributes().removeNamedItem(att.getNodeName()); } } /** * Remove all children from a node. * * @param node */ public static void clearChildren(Node node) { while (node.hasChildNodes()) node.removeChild(node.getFirstChild()); } /** * Determine if a block contains a new line. * * @param n * @return */ public static boolean containsNL(Node n) { Node child = n.getFirstChild(); while (child != null) { if (child.getNodeType() == Node.TEXT_NODE) { if (child.getNodeValue().contains("\n")) return true; } child = child.getNextSibling(); } return false; } /** * Combine all text with neighbors in immediate children. * * @param node */ public static void combineText(Node node) { // merge text nodes Node child = node.getFirstChild(); while (child != null) { Node next = child.getNextSibling(); if (child.getNodeType() != Node.TEXT_NODE) { child = next; continue; } if (next != null && next.getNodeType() == Node.TEXT_NODE) { child.setTextContent(child.getNodeValue() + next.getNodeValue()); child.getParentNode().removeChild(next); continue; } child = next; } } /** * Merge the contents of a node with its parent. * * @param parent * @param node */ public static void mergeNode(Node parent, Node node) { while (node.hasChildNodes()) { parent.insertBefore(node.getFirstChild(), node); } parent.removeChild(node); } static void transferContents(Node dest, Node source) { while (source.hasChildNodes()) { dest.appendChild(source.getFirstChild()); } } /** * Traverse a node and replaces all extra whitespace with one space. * * This should be applied to any element where white space is not relevant. * * @param node */ public static void removeWhitespace(Node node) { // merge text nodes NodeList children = node.getChildNodes(); for (int i = 0; i < children.getLength(); ++i) { Node child = children.item(i); if (child.getNodeType() != Node.TEXT_NODE) continue; Text t = (Text) child; String c = t.getNodeValue(); if (c != null) { c = c.replaceAll("\\s+", " "); t.setNodeValue(c); } } } } jpype-1.3.0/native/java/org/jpype/javadoc/Javadoc.java000066400000000000000000000023561405671516700226320ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype.javadoc; import java.util.HashMap; import java.util.List; import java.util.Map; import org.w3c.dom.Node; public class Javadoc { public String description; public String ctors; public Map methods = new HashMap<>(); public Map fields = new HashMap<>(); // These will be removed once debugging is complete public Node descriptionNode; public List ctorsNode; public List methodNodes; public List innerNode; public List fieldNodes; } jpype-1.3.0/native/java/org/jpype/javadoc/JavadocException.java000066400000000000000000000017101405671516700245020ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype.javadoc; import org.w3c.dom.Node; public class JavadocException extends RuntimeException { public Node node; public JavadocException(Node node, Throwable th) { super(th); this.node = node; } } jpype-1.3.0/native/java/org/jpype/javadoc/JavadocExtractor.java000066400000000000000000000167021405671516700245260ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype.javadoc; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import org.jpype.html.Html; import org.jpype.html.Parser; import org.w3c.dom.Document; import org.w3c.dom.DocumentFragment; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public class JavadocExtractor { static final JavadocTransformer transformer = new JavadocTransformer(); static public boolean transform = true; static public boolean render = true; static public boolean failures = false; /** * Search the classpath for documentation. * * @param cls * @return */ public static Javadoc getDocumentation(Class cls) { try { try (InputStream is = getDocumentationAsStream(cls)) { if (is != null) { Parser parser = Html.newParser(); return extractDocument(cls, parser.parse(is)); } } } catch (Exception ex) { System.err.println("Failed to extract javadoc for " + cls); if (failures) throw new RuntimeException(ex); } return null; } public static InputStream getDocumentationAsStream(Class cls) { InputStream is = null; String name = cls.getName().replace('.', '/') + ".html"; ClassLoader cl = ClassLoader.getSystemClassLoader(); // Search the regular class path. is = cl.getResourceAsStream(name); if (is != null) return is; // Search for api documents String name1 = "docs/api/" + name; is = cl.getResourceAsStream(name1); if (is != null) return is; // If we are dealing with Java 9+, the doc tree is different try { Method meth = Class.class.getMethod("getModule"); String module = meth.invoke(cls).toString().substring(7); String name2 = "docs/api/" + module + "/" + name; is = cl.getResourceAsStream(name2); if (is != null) return is; } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { // do nothing if we are not JDK 9+ } return null; } /** * Extract the documentation from the dom. * * @param cls is the class being processed. * @param doc is the DOM holding the javadoc. * @return */ public static Javadoc extractDocument(Class cls, Document doc) { JavadocRenderer renderer = new JavadocRenderer(); try { Javadoc documentation = new Javadoc(); XPath xPath = XPathFactory.newInstance().newXPath(); Node description = toFragment((Node) xPath.compile("//div[@class='description']/ul/li").evaluate(doc, XPathConstants.NODE)); if (description != null) { documentation.descriptionNode = description; if (transform) transformer.transformDescription(cls, description); if (render) documentation.description = renderer.render(description); } Node ctorRoot = ((Node) xPath.compile("//li/a[@name='constructor.detail' or @id='constructor.detail']") .evaluate(doc, XPathConstants.NODE)); if (ctorRoot != null) { List set = convertNodes((NodeList) xPath.compile("./ul/li") .evaluate(ctorRoot.getParentNode(), XPathConstants.NODESET)); documentation.ctorsNode = set; StringBuilder sb = new StringBuilder(); for (Node ctor : set) { if (transform) transformer.transformMember(cls, ctor); if (render) sb.append(renderer.render(ctor)); } documentation.ctors = sb.toString(); } Node methodRoot = ((Node) xPath.compile("//li/a[@name='method.detail' or @id='method.detail']") .evaluate(doc, XPathConstants.NODE)); if (methodRoot != null) { List set = convertNodes((NodeList) xPath.compile("./ul/li") .evaluate(methodRoot.getParentNode(), XPathConstants.NODESET)); documentation.methodNodes = set; for (Node method : set) { if (transform) transformer.transformMember(cls, method); if (render) { String str = renderer.render(method); String name = renderer.memberName; if (documentation.methods.containsKey(name)) { String old = documentation.methods.get(name); str = old + str; } documentation.methods.put(name, str); } } } // Node inner = (Node) xPath.compile("//li/a[@name='nested_class_summary']").evaluate(doc, XPathConstants.NODE); // if (inner != nullList) // { // NodeList set = (NodeList) xPath.compile("./ul/li").evaluate(inner.getParentNode(), XPathConstants.NODESET); // documentation.innerNode = convertNodes(set); // } Node fieldRoot = ((Node) xPath.compile("//li/a[@name='field.detail' or @id='field.detail']") .evaluate(doc, XPathConstants.NODE)); if (fieldRoot != null) { List set = convertNodes((NodeList) xPath.compile("./ul/li") .evaluate(fieldRoot.getParentNode(), XPathConstants.NODESET)); documentation.fieldNodes = set; for (Node field : set) { if (transform) transformer.transformMember(cls, field); if (render) { String str = renderer.render(field); String name = renderer.memberName; documentation.fields.put(name, str); } } } return documentation; } catch (IOException | XPathExpressionException ex) { throw new RuntimeException(ex); // return null; } } private static List convertNodes(NodeList nl) throws IOException { List out = new ArrayList<>(); for (int i = 0; i < nl.getLength(); ++i) { out.add(toFragment(nl.item(i))); } return out; } /** * Convert a portion of the document into a fragment. * * @param node * @return */ public static Node toFragment(Node node) { Document doc = node.getOwnerDocument(); DocumentFragment out = doc.createDocumentFragment(); while (node.hasChildNodes()) { out.appendChild(node.getFirstChild()); } if (out.getFirstChild() != null && out.getFirstChild().getNodeType() == Node.TEXT_NODE) out.removeChild(out.getFirstChild()); if (out.getLastChild() != null && out.getLastChild().getNodeType() == Node.TEXT_NODE) out.removeChild(out.getLastChild()); return out; } } jpype-1.3.0/native/java/org/jpype/javadoc/JavadocRenderer.java000066400000000000000000000253141405671516700243200ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype.javadoc; import java.nio.charset.StandardCharsets; import org.w3c.dom.Element; import org.w3c.dom.Node; import java.util.Map; import java.util.HashMap; /** * Render a node as ReStructured Text. * * @author nelson85 */ public class JavadocRenderer { static final int WIDTH = 120; public StringBuilder assembly; public int indentLevel = 0; String memberName; public String render(Node node) { try { indentLevel = 0; assembly = new StringBuilder(); DomUtilities.traverseChildren(node, this::renderSections, Node.ELEMENT_NODE); return assembly.toString(); } catch (Exception ex) { throw new JavadocException(node, ex); } } /** * Render the dom into restructured text. * * @param node */ void renderSections(Node node) { Element e = (Element) node; String name = e.getTagName(); if (name.equals("title")) { this.memberName = node.getTextContent(); return; } if (name.equals("signature")) { assembly.append(node.getTextContent()) .append("\n\n"); indentLevel += 4; return; } if (name.equals("description")) { renderText(node, true, true); return; } if (name.equals("details")) { DomUtilities.traverseChildren(node, this::renderDetails, Node.ELEMENT_NODE); assembly.append("\n"); return; } } final static Map SECTIONS = new HashMap<>(); static { // Decide what sections to render SECTIONS.put("returns", "Returns:"); SECTIONS.put("see", "See also:"); SECTIONS.put("since", "Since:"); SECTIONS.put("jls", "See Java\u2122 specification:"); SECTIONS.put("overrides", "Overrides:"); SECTIONS.put("specified", "Specified by:"); SECTIONS.put("version", null); SECTIONS.put("typeparams", null); SECTIONS.put("author", null); SECTIONS.put("see", "Also see:"); SECTIONS.put("api_note", "API Note:"); SECTIONS.put("requirements", "Implementation Requirements:"); SECTIONS.put("impl_note", "Implementation Note:"); } void renderDetails(Node node) { String name = node.getNodeName(); if (name.equals("parameters")) { assembly.append('\n') .append(indentation(this.indentLevel)) .append("Parameters:\n"); indentLevel += 4; DomUtilities.traverseChildren(node, this::renderParameter, Node.ELEMENT_NODE); indentLevel -= 4; } else if (name.equals("throws")) { assembly.append('\n') .append(indentation(this.indentLevel)) .append("Raises:\n"); indentLevel += 4; DomUtilities.traverseChildren(node, this::renderThrow, Node.ELEMENT_NODE); indentLevel -= 4; } else if (SECTIONS.containsKey(name)) { String title = SECTIONS.get(name); if (title == null) return; assembly.append('\n') .append(indentation(this.indentLevel)) .append(title).append('\n'); indentLevel += 4; renderText(node, true, true); indentLevel -= 4; } else { System.err.println("Need renderer for section " + name); } } void renderParameter(Node node) { Element elem = (Element) node; assembly.append(indentation(this.indentLevel)) // .append(" ") .append(elem.getAttribute("name")) .append(" (") .append(elem.getAttribute("type")) .append("): "); indentLevel += 4; renderText(node, false, true); indentLevel -= 4; } void renderThrow(Node node) { Element elem = (Element) node; assembly.append(indentation(this.indentLevel)) //.append(" ") .append(elem.getAttribute("name")) .append(": "); indentLevel += 4; renderText(node, false, true); indentLevel -= 4; } /** * Render a paragraph or paragraph like element. * */ void renderText(Node node, boolean startIndent, boolean trailingNL) { DomUtilities.combineText(node); DomUtilities.removeWhitespace(node); Node child = node.getFirstChild(); for (; child != null; child = child.getNextSibling()) { if (child.getNodeType() == Node.TEXT_NODE) { String value = child.getNodeValue(); if (value == null) continue; value = value.trim(); if (value.isEmpty()) continue; formatWidth(assembly, value, WIDTH, indentLevel, startIndent); if (trailingNL) assembly.append("\n"); continue; } if (child.getNodeType() != Node.ELEMENT_NODE) continue; Element element = (Element) child; String name = element.getTagName(); if (name.equals("p")) { assembly.append("\n"); renderText(element, true, true); } else if (name.equals("div")) { renderText(element, true, true); } else if (name.equals("center")) { renderText(element, true, true); } else if (name.equals("br")) { assembly.append("\n\n"); } else if (name.equals("ul")) { renderUnordered(element); } else if (name.equals("ol")) { renderOrdered(element); } else if (name.equals("img")) { // punt } else if (name.equals("table")) { // punt } else if (name.equals("hr")) { // punt } else if (name.equals("dl")) { renderDefinitions(element); } else if (name.equals("codeblock")) { renderCodeBlock(element); } else if (name.equals("blockquote")) { renderBlockQuote(element); } else if (name.equals("h1")) { renderHeader(element); } else if (name.equals("h2")) { renderHeader(element); } else if (name.equals("h3")) { renderHeader(element); } else if (name.equals("h4")) { renderHeader(element); } else if (name.equals("h5")) { renderHeader(element); } else { throw new RuntimeException("Need render for " + name); } } } void renderHeader(Node node) { assembly.append("\n"); renderText(node, true, true); assembly.append(new String(new byte[node.getTextContent().length()]).replace('\0', '-')) .append("\n\n"); } void renderBlockQuote(Node node) { indentLevel += 4; renderText(node, true, true); indentLevel -= 4; } /** * Render an unordered list. * * @param node */ void renderOrdered(Node node) { indentLevel += 4; assembly.append("\n"); Node child = node.getFirstChild(); int num = 1; for (; child != null; child = child.getNextSibling()) { if (child.getNodeType() != Node.ELEMENT_NODE) continue; if (child.getNodeName().equals("li")) { assembly.append(indentation(indentLevel - 2)) .append(String.format("%d. ", num++)); renderText(child, false, true); } else throw new RuntimeException("Bad node " + child.getNodeName() + " in UL"); } indentLevel -= 4; assembly.append("\n"); } /** * Render an unordered list. * * @param node */ void renderUnordered(Node node) { indentLevel += 4; assembly.append("\n"); Node child = node.getFirstChild(); for (; child != null; child = child.getNextSibling()) { if (child.getNodeType() != Node.ELEMENT_NODE) continue; if (child.getNodeName().equals("li")) { assembly.append(indentation(indentLevel - 4)) .append(" - "); renderText(child, false, true); } else throw new RuntimeException("Bad node " + child.getNodeName() + " in UL"); } indentLevel -= 4; assembly.append("\n"); } /** * Render a definition list. * * @param node */ void renderDefinitions(Node node) { Node child = node.getFirstChild(); for (; child != null; child = child.getNextSibling()) { if (child.getNodeType() != Node.ELEMENT_NODE) continue; String name = child.getNodeName(); if (name.equals("dt")) { assembly.append("\n"); renderText(child, true, true); } else if (name.equals("dd")) { assembly.append(indentation(indentLevel)); indentLevel += 4; assembly.append(" "); renderText(child, false, true); indentLevel -= 4; } else throw new RuntimeException("Bad node " + name + " in DL"); } assembly.append("\n"); } void renderCodeBlock(Node node) { String indent = indentation(indentLevel); assembly.append("\n") .append(indent) .append(".. code-block: java\n"); String text = node.getTextContent(); if (text.charAt(0) != '\n') text = "\n" + text; text = text.replaceAll("\n", "\n" + indent); assembly.append(indent).append(text).append("\n"); } // static final String SPACING = new String(new byte[40]).replace('\0', ' '); static String indentation(int level) { if (level > 40) return new String(); return SPACING.substring(0, level); } static void formatWidth(StringBuilder sb, String s, int width, int indent, boolean flag) { String sindent = indentation(indent); s = s.replaceAll("\\s+", " ").trim(); if (s.length() < width) { if (flag) sb.append(sindent); sb.append(s); return; } byte[] b = s.getBytes(StandardCharsets.UTF_8); int start = 0; int prev = 0; int l = b.length; int next = 0; while (next < l) { for (next = prev + 1; next < l; ++next) if (b[next] == ' ') break; if (next - start > width) { b[prev] = '\n'; if (flag) sb.append(sindent); flag = true; sb.append(new String(b, start, prev - start + 1)); start = prev + 1; } prev = next; } sb.append(sindent); sb.append(new String(b, start, l - start)); } // } jpype-1.3.0/native/java/org/jpype/javadoc/JavadocTransformer.java000066400000000000000000000331531405671516700250540ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype.javadoc; import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashMap; import java.util.LinkedList; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.jpype.html.Html; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.Text; /** * Transform the document into a form suitable for ReStructured Text. * * The goal of this is to convert all inline markup into rst and leave markup by * section, paragraph to be used by the renderer. * * @author nelson85 */ public class JavadocTransformer { final static Pattern ARGS_PATTERN = Pattern.compile(".*\\((.*)\\).*"); public Node transformDescription(Class cls, Node node) { try { Workspace ws = new Workspace(cls); DomUtilities.traverseDFS(node, this::fixEntities, Node.TEXT_NODE); DomUtilities.traverseChildren(node, this::handleDescription, Node.ELEMENT_NODE, ws); DomUtilities.traverseDFS(node, this::pass1, Node.ELEMENT_NODE, ws); return node; } catch (Exception ex) { throw new JavadocException(node, ex); } } /** * Convert a Javadoc member description into markup for ReStructure Text * rendering. * * This will mutilate the node. * * @param node */ public Node transformMember(Class cls, Node node) { try { Workspace ws = new Workspace(cls); DomUtilities.traverseDFS(node, this::fixEntities, Node.TEXT_NODE); DomUtilities.traverseChildren(node, this::handleMembers, Node.ELEMENT_NODE, ws); DomUtilities.traverseDFS(node, this::pass1, Node.ELEMENT_NODE, ws); return node; } catch (Exception ex) { throw new JavadocException(node, ex); } } // void handleDescription(Node node, Workspace data) { Element e = (Element) node; String name = e.getTagName(); Document doc = e.getOwnerDocument(); Node parent = node.getParentNode(); if (name.equals("dl") && !data.hr) { parent.removeChild(node); } else if (name.equals("br")) { parent.removeChild(node); } else if (name.equals("hr")) { data.hr = true; parent.removeChild(node); } else if (name.equals("pre")) { DomUtilities.removeWhitespace(node); doc.renameNode(node, null, "signature"); } else if (name.equals("div")) { doc.renameNode(node, null, "description"); DomUtilities.clearAttributes(node); } else if (name.equals("dl")) { doc.renameNode(node, null, "details"); DomUtilities.traverseChildren(node, this::handleDetails, Node.ELEMENT_NODE, data); } else { throw new RuntimeException("Unknown item at top level " + name); } } // // void handleMembers(Node node, Workspace ws) { Element e = (Element) node; String name = e.getTagName(); Document doc = e.getOwnerDocument(); if (name.equals("h4")) { doc.renameNode(node, null, "title"); } else if (name.equals("pre")) { doc.renameNode(node, null, "signature"); DomUtilities.traverseDFS(node, this::pass1, Node.ELEMENT_NODE, ws); // We need to get the types from here for the parameters DomUtilities.removeWhitespace(node); String content = node.getTextContent(); Matcher m = ARGS_PATTERN.matcher(content); if (m.matches()) { LinkedList types = new LinkedList<>(); for (String s : m.group(1).split(", ")) { String[] parts = s.split("\u00a0", 2); types.add(parts[0]); } ws.types = types; } } else if (name.equals("div")) { doc.renameNode(node, null, "description"); DomUtilities.clearAttributes(node); } else if (name.equals("dl")) { doc.renameNode(node, null, "details"); DomUtilities.traverseChildren(node, this::handleDetails, Node.ELEMENT_NODE, ws); } else { throw new RuntimeException("Unknown item at top level " + name); } } public final static Map DETAIL_SECTIONS; static { DETAIL_SECTIONS = new HashMap<>(); Map ds = DETAIL_SECTIONS; ds.put("Author:", "author"); ds.put("Since:", "since"); ds.put("Parameters:", "parameters"); ds.put("Returns:", "returns"); ds.put("Overrides:", "overrides"); ds.put("See Also:", "see"); ds.put("API Note:", "api_note"); ds.put("Version:", "version"); ds.put("Type Parameters:", "typeparams"); ds.put("Specified by:", "specified"); ds.put("Throws:", "throws"); ds.put("Implementation Requirements:", "requirements"); ds.put("Implementation Note:", "impl_note"); } void handleDetails(Node node, Workspace ws) { Element e = (Element) node; String name = e.getTagName(); Document doc = e.getOwnerDocument(); Node parent = e.getParentNode(); if (name.equals("dt")) { String key = node.getTextContent().trim(); if (DETAIL_SECTIONS.containsKey(key)) { doc.renameNode(node, null, DETAIL_SECTIONS.get(key)); } else if (key.startsWith("See ")) { doc.renameNode(node, null, "jls"); } else { System.err.println("Bad detail key '" + key + "'"); } ws.key = node.getNodeName(); ws.section = node; DomUtilities.clearChildren(ws.section); } if (name.equals("dd")) { if (ws.key.equals("parameters")) { Node first = node.getFirstChild(); // First is varname Node second = first.getNextSibling(); // Second is " - desc" Element elem = doc.createElement("parameter"); elem.setAttribute("name", first.getTextContent()); elem.setAttribute("type", ws.types.removeFirst()); String value = second.getNodeValue(); second.setNodeValue(value.substring(3)); // Remove " - " node.removeChild(first); DomUtilities.transferContents(elem, node); ws.section.appendChild(elem); parent.removeChild(node); } else if (ws.key.equals("throws")) { Node first = node.getFirstChild(); // First is exc Node second = first.getNextSibling(); // Second is " - desc" Element elem = doc.createElement("exception"); DomUtilities.traverseDFS(first, this::pass1, Node.ELEMENT_NODE, ws); elem.setAttribute("name", first.getTextContent()); if (second != null) { String value = second.getNodeValue(); second.setNodeValue(value.substring(3)); // Remove " - " } node.removeChild(first); DomUtilities.transferContents(elem, node); ws.section.appendChild(elem); parent.removeChild(node); } else { // Normalize the node and transfer it to the section DomUtilities.transferContents(ws.section, node); DomUtilities.traverseDFS(ws.section, this::pass1, Node.ELEMENT_NODE, ws); DomUtilities.removeWhitespace(ws.section); parent.removeChild(node); return; } } } static class Workspace { private final Class cls; boolean hr = false; String key; Node section; private LinkedList types; Workspace(Class cls) { this.cls = cls; } } // // /** * Convert any html entities found the text. * * @param node */ void fixEntities(Node node) { Text n = (Text) node; String s = Html.decode(n.getTextContent()); n.setTextContent(s); } // This corresponds to any simple inline markup transformation. final static String[] PASS1 = new String[] { "cite", "\"%s\"", "code", ":code:`%s`", "pre", ":code:`%s`", "tt", "``%s``", "i", "*%s*", "em", "*%s*", "strong", "**%s**", "b", "**%s**", "sup", " :sup:`%s` ", "sub", " :sub:`%s` ", "small", ":sub:`%s`", "span", "%s", "nop", "%s", "font", "%s", "var", "*%s*", }; /** * Get a bunch of simple substitutions. * * @param node */ void pass1(Node node, Workspace ws) { Element e = (Element) node; String name = e.getTagName(); Document doc = e.getOwnerDocument(); Node parent = e.getParentNode(); if (parent == null) return; // Pre is something used to mark code. if (name.equals("pre")) { if (DomUtilities.containsNL(e)) { doc.renameNode(node, null, "codeblock"); name = "codeblock"; } else { doc.renameNode(node, null, "code"); name = "code"; } } //

 is a common javadoc idiom.
    if (name.equals("code") && (parent.getNodeName().equals("pre")
            || parent.getNodeName().equals("blockquote")))
    {
      doc.renameNode(parent, null, "codeblock");
      DomUtilities.mergeNode(parent, node);
      return;
    }

    if (name.equals("codeblock") && parent.getNodeName().equals("pre"))
    {
      if (DomUtilities.containsNL(node))
      {
        doc.renameNode(parent, null, "codeblock");
      } else
        doc.renameNode(parent, null, "code");
      DomUtilities.mergeNode(parent, node);
      return;
    }

    //  is used to reference members and classes.
    if (name.equals("code") && parent.getNodeName().equals("a"))
    {
      Element eparent = (Element) parent;
      String href = this.toReference(ws, eparent.getAttribute("href"));
      DomUtilities.clearChildren(parent);
      parent.appendChild(doc.createTextNode(href));
      return;
    }

    //  is also used.
    if (name.equals("a") && parent.getNodeName().equals("code"))
    {
      String href = this.toReference(ws, e.getAttribute("href"));
      DomUtilities.clearChildren(parent);
      doc.renameNode(parent, null, "nop");
      parent.appendChild(doc.createTextNode(href));
      return;
    }

    //  by itself is usually external references.
    if (name.equals("a"))
    {
      String href = e.getAttribute("href");
      if (href.startsWith("http:") || href.startsWith("shttp:"))
      {
        String content = node.getTextContent();
        content = String.format("`%s <%s>`", content, href);
        parent.replaceChild(doc.createTextNode(content), node);
        return;
      }
      href = this.toReference(ws, href);
      if (href == null)
        parent.replaceChild(doc.createTextNode(node.getTextContent()), node);
      else
        parent.replaceChild(doc.createTextNode(href), node);
      return;
    }

    // Apply inline transformations.
    for (int i = 0; i < PASS1.length; i += 2)
    {
      if (name.equals(PASS1[i]))
      {
        String s2 = e.getTextContent();
        if (s2 == null)
          e.getParentNode().removeChild(e);
        else
          e.getParentNode().replaceChild(doc.createTextNode(String.format(PASS1[i + 1], s2.trim())), e);
        return;
      }
    }

  }

  /**
   * Convert a reference into method or class.
   *
   * This currently only deals with local links. External links are elsewhere.
   *
   * @param ws
   * @param href
   * @return
   */
  public String toReference(Workspace ws, String href)
  {
    try
    {
      Path p = Paths.get(ws.cls.getName().replace('.', '/'));
      if (href.startsWith("#"))
      {
        // technically it may be a field, but we can't tell currently.
        Path q = p.resolve(href.substring(1).trim())
                .normalize();
        if (q.startsWith(".."))
          q = q.subpath(2, q.getNameCount());
        String r = q.toString()
                .replace('/', '.')
                .replace('\\', '.')
                .replaceAll("\\(.*\\)", "")
                .replaceAll("-.*", "");
        return String.format(":meth:`~%s`", r);
      } else if (href.contains("#"))
      {
        // technically it may be a field, but we can't tell currently.
        Path q = p.getParent()
                .resolve(href.trim())
                .normalize();
        if (q.startsWith(".."))
          q = q.subpath(2, q.getNameCount());
        String r = q.toString()
                .replace('/', '.')
                .replace('\\', '.')
                .replaceAll("\\(.*\\)", "")
                .replaceAll("-.*", "")
                .replaceAll(".html#", ".");
        return String.format(":meth:`~%s`", r);
      } else
      {
        Path q = p.getParent()
                .resolve(href.trim())
                .normalize();
        if (q.startsWith(".."))
          q = q.subpath(2, q.getNameCount());
        String r = q.toString()
                .replace('/', '.')
                .replace('\\', '.')
                .replaceAll("-.*", "")
                .replaceAll(".html", "");
        return String.format(":class:`~%s`", r);
      }
    } catch (Exception ex)
    {
      // There is a lot of ways this can go wrong.  If all else fails
      // return null so that we can just remove the hyperlink.
      return null;
    }
  }

//
}
jpype-1.3.0/native/java/org/jpype/manager/000077500000000000000000000000001405671516700204155ustar00rootroot00000000000000jpype-1.3.0/native/java/org/jpype/manager/ClassDescriptor.java000066400000000000000000000035021405671516700243640ustar00rootroot00000000000000/* ****************************************************************************
  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

  See NOTICE file for details.
**************************************************************************** */
package org.jpype.manager;

import java.lang.reflect.Executable;
import java.lang.reflect.Method;

/**
 * A list of resources associated with this class.
 * 

* These can be accessed within JPype using the org.jpype.manager.TypeManager. *

*/ public class ClassDescriptor { public Class cls; /** * JPClass pointer for this class. */ public long classPtr; /** * JPMethodDispatch for the constructor. */ public long constructorDispatch; public long[] constructors; /** * Resources needed by the class */ public long[] methodDispatch; public Executable[] methodIndex; public long[] methods; public int methodCounter = 0; public long[] fields; public long anonymous; ClassDescriptor(Class cls, long classPtr) { this.cls = cls; this.classPtr = classPtr; if (this.classPtr == 0) throw new NullPointerException("Class pointer is null for " + cls); } long getMethod(Method requestedMethod) { for (int i = 0; i < methods.length; ++i) if (this.methodIndex[i].equals(requestedMethod)) return this.methods[i]; return 0; } } jpype-1.3.0/native/java/org/jpype/manager/MethodResolution.java000066400000000000000000000205701405671516700245700ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype.manager; import java.lang.reflect.Executable; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.LinkedList; import java.util.List; /** * Sort out which methods hide other methods. *

* When resolving method overloads there may be times in which more than one * overload applies. JPype requires that the methods appear in order from most * to least specific. And each method overload requires a list of methods that * are more general. If two or more methods match and one is not more specific * than the other. * * @author nelson85 */ public class MethodResolution { long ptr = 0; boolean covered = false; Executable executable; List children = new ArrayList<>(); MethodResolution(Executable method) { this.executable = method; } private boolean isCovered() { for (MethodResolution ov : this.children) { if (!ov.covered) return false; } covered = true; return true; } /** * Order methods from least to most specific. * * @param * @param methods * @return */ public static List sortMethods(List methods) { // Create a method resolution for each method LinkedList unsorted = new LinkedList<>(); for (T m1 : methods) { unsorted.add(new MethodResolution(m1)); } for (MethodResolution m1 : unsorted) { for (MethodResolution m2 : unsorted) { if (m1 == m2) continue; if (isMoreSpecificThan(m1.executable, m2.executable) && !isMoreSpecificThan(m2.executable, m1.executable)) { m1.children.add(m2); } } } // Execute a graph sort problem so that the most specific are always on the front LinkedList out = new LinkedList<>(); while (!unsorted.isEmpty()) { // Remove the first unsorted element MethodResolution front = unsorted.pop(); // Check to see if all dependencies are already ordered boolean good = front.isCovered(); // If all dependencies are included if (good) { front.covered = true; out.add(front); } else { unsorted.add(front); } } return out; } // Table for primitive rules static Class[] of(Class... l) { return l; } static HashMap CONVERSION = new HashMap<>(); { CONVERSION.put(Byte.TYPE, of(Byte.TYPE, Byte.class, Short.TYPE, Short.class, Integer.TYPE, Integer.class, Long.TYPE, Long.class, Float.TYPE, Float.class, Double.TYPE, Double.class)); CONVERSION.put(Character.TYPE, of(Character.TYPE, Character.class, Short.TYPE, Short.class, Integer.TYPE, Integer.class, Long.TYPE, Long.class, Float.TYPE, Float.class, Double.TYPE, Double.class)); CONVERSION.put(Short.TYPE, of(Short.TYPE, Short.class, Integer.TYPE, Integer.class, Long.TYPE, Long.class, Float.TYPE, Float.class, Double.TYPE, Double.class)); CONVERSION.put(Integer.TYPE, of(Integer.TYPE, Integer.class, Long.TYPE, Long.class, Float.TYPE, Float.class, Double.TYPE, Double.class)); CONVERSION.put(Long.TYPE, of(Long.TYPE, Long.class, Float.TYPE, Float.class, Double.TYPE, Double.class)); CONVERSION.put(Float.TYPE, of(Float.TYPE, Float.class, Double.TYPE, Double.class)); CONVERSION.put(Double.TYPE, of(Double.TYPE, Double.class)); CONVERSION.put(Boolean.TYPE, of(Boolean.TYPE, Boolean.class)); } static boolean isAssignableTo(Class c1, Class c2) { if (!c1.isPrimitive()) return c2.isAssignableFrom(c1); Class[] cl = CONVERSION.get(c1); if (cl == null) return false; for (Class c3 : cl) if (c2.equals(c3)) return true; return false; } /** * Determine is a executable is more specific than another. *

* This is public so that we can debug from within jpype. * * @param method1 * @param method2 * @return */ public static boolean isMoreSpecificThan(Executable method1, Executable method2) { List> param1 = new ArrayList<>(Arrays.asList(method1.getParameterTypes())); List> param2 = new ArrayList<>(Arrays.asList(method2.getParameterTypes())); if (!Modifier.isStatic(method1.getModifiers())) param1.add(0, method1.getDeclaringClass()); if (!Modifier.isStatic(method2.getModifiers())) param2.add(0, method2.getDeclaringClass()); // Special handling is needed for varargs as it may chop or expand. // we have 4 cases for a varargs methods // foo(Arg0, Arg1...) as // foo(Arg0) // foo(Arg0, Arg1) // foo(Arg0, Arg1[]) // foo(Arg0, Arg1, Arg1+) if (method1.isVarArgs() && method2.isVarArgs()) { // Punt on this as there are too many different cases return isMoreSpecificThan(param1, param2); } if (method1.isVarArgs()) { int n1 = param1.size(); int n2 = param2.size(); // Last element is an array Class cls = param1.get(n1 - 1); Class cls2 = cls.getComponentType(); // Less arguments, chop the list if (n1 - 1 == n2) return isMoreSpecificThan(param1.subList(0, n2), param2); // Same arguments if (n1 == n2) { List> q = new ArrayList<>(param1); q.set(n1 - 1, cls2); // Check both ways boolean isMoreSpecific = isMoreSpecificThan(param1, param2) || isMoreSpecificThan(q, param2); // If the varargs array is of the single-variable's type (or they are primitive-equivalent), // the single-variable signature should win specificity Class svCls = param2.get(n2-1); return isMoreSpecific && !(isAssignableTo(cls2, svCls) && isAssignableTo(svCls, cls2)); } // More arguments if (n1 < n2) { // Grow the list List> q = new ArrayList<>(param1); q.set(n1 - 1, cls2); for (int i = n1; i < n2; ++i) q.add(cls2); return isMoreSpecificThan(q, param2); } } if (method2.isVarArgs()) { int n1 = param1.size(); int n2 = param2.size(); // Last element is an array Class cls = param2.get(n2 - 1); Class cls2 = cls.getComponentType(); // Less arguments, chop the list if (n2 - 1 == n1) return isMoreSpecificThan(param1, param2.subList(0, n2)); // Same arguments if (n1 == n2) { List> q = new ArrayList<>(param2); q.set(n2 - 1, cls2); // Compare both ways return isMoreSpecificThan(param1, param2) || isMoreSpecificThan(param1, q); } // More arguments if (n2 < n1) { // Grow the list List> q = new ArrayList<>(param2); q.set(n2 - 1, cls2); for (int i = n2; i < n1; ++i) q.add(cls2); return isMoreSpecificThan(param1, q); } } return isMoreSpecificThan(param1, param2); } public static boolean isMoreSpecificThan(List> param1, List> param2) { // FIXME need to consider resolving mixing of static and non-static // Methods here. if (param1.size() != param2.size()) return false; for (int i = 0; i < param1.size(); ++i) { if (!isAssignableTo(param1.get(i), param2.get(i))) return false; } return true; } } jpype-1.3.0/native/java/org/jpype/manager/ModifierCode.java000066400000000000000000000042631405671516700236160ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype.manager; import java.lang.reflect.Modifier; import java.util.EnumSet; /** * Definitions for JPype modifiers. *

* These pretty much match Java plus a few codes we need. * * @author nelson85 */ public enum ModifierCode { // we need // fields: static, final // methods: static, final, varargs, constructor // class: interface, throwable, abstract, final PUBLIC(Modifier.PUBLIC), PRIVATE(Modifier.PRIVATE), PROTECTED(Modifier.PROTECTED), STATIC(Modifier.STATIC), FINAL(Modifier.FINAL), VARARGS(0x0080), ENUM(0x4000), ABSTRACT(0x0400), // Special flags for classes required for JPype SPECIAL(0x00010000), THROWABLE(0x00020000), SERIALIZABLE(0x00040000), ANONYMOUS(0x00080000), FUNCTIONAL(0x00100000), CALLER_SENSITIVE(0x00200000), PRIMITIVE_ARRAY(0x00400000), COMPARABLE(0x00800000), BUFFER(0x01000000), CTOR(0x10000000), BEAN_ACCESSOR(0x20000000), BEAN_MUTATOR(0x40000000); final public int value; ModifierCode(int value) { this.value = value; } public static int get(EnumSet set) { int out = 0; for (ModifierCode m : set) { out |= m.value; } return out; } public static EnumSet decode(long modifiers) { EnumSet out = EnumSet.noneOf(ModifierCode.class); for (ModifierCode code : ModifierCode.values()) { if ((modifiers & code.value) == code.value) out.add(code); } return out; } } jpype-1.3.0/native/java/org/jpype/manager/TypeAudit.java000066400000000000000000000021241405671516700231670ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype.manager; import java.lang.reflect.Method; /** * Auditing class for TypeManager used during testing. *

* This is not used during operation. * * @author nelson85 */ public interface TypeAudit { void dump(ClassDescriptor desc); void verifyMembers(ClassDescriptor desc); public void failFindMethod(ClassDescriptor desc, Method method); } jpype-1.3.0/native/java/org/jpype/manager/TypeFactory.java000066400000000000000000000117451405671516700235410ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype.manager; import java.lang.reflect.Executable; import java.lang.reflect.Field; /** * Interface for creating new resources used by JPype. *

* This calls the C++ constructors with all of the required fields for each * class. This pattern eliminates the need for C++ layer probing Java for * resources. *

* This is an interface for testing. * * @author nelson85 */ public interface TypeFactory { // /** * Create a new wrapper type for Python. * * @param context * @param cls is the pointer to the JClass. */ void newWrapper(long context, long cls); /** * Create a JPArray class. * * @param context JPContext object * @param cls is the class type. * @param name * @param superClass * @param componentPtr * @param modifiers * @return the pointer to the JPArrayClass. */ long defineArrayClass( long context, Class cls, String name, long superClass, long componentPtr, int modifiers); /** * Create a class type. * * @param context JPContext object * @param cls * @param superClass * @param interfaces * @param modifiers * @param name * @return the pointer to the JPClass. */ long defineObjectClass( long context, Class cls, String name, long superClass, long[] interfaces, int modifiers); /** * Define a primitive types. * * @param context JPContext object * @param cls is the Java class for this primitive. * @param boxedPtr is the JPClass for the boxed class. * @param modifiers * @return */ long definePrimitive( long context, String name, Class cls, long boxedPtr, int modifiers); // // /** * Called after a class is constructed to populate the required fields and * methods. * * @param context JPContext object * @param cls is the JPClass to populate * @param ctorMethod is the JPMethod for the constructor. * @param methodList is a list of JPMethod for the method list. * @param fieldList is a list of JPField for the field list. */ void assignMembers( long context, long cls, long ctorMethod, long[] methodList, long[] fieldList); /** * Create a Method. * * @param context JPContext object * @param cls is the class holding this. * @param name * @param field * @param fieldType * @param modifiers * @return the pointer to the JPMethod. */ long defineField( long context, long cls, String name, Field field, // This will convert to a field id long fieldType, int modifiers); /** * Create a Method. * * @param context JPContext object * @param cls is the class holding this. * @param name * @param method is the Java method that will be called, converts to a method * id. * @param overloadList * @param modifiers * @return the pointer to the JPMethod. */ long defineMethod( long context, long cls, String name, Executable method, long[] overloadList, int modifiers); void populateMethod( long context, long method, long returnType, long[] argumentTypes); /** * Create a Method dispatch for Python by name. * * @param context JPContext object * @param cls is the class that owns this dispatch. * @param name is the name of the dispatch. * @param overloadList is the list of all methods constructed for this class. * @param modifiers contains if the method is (CTOR, STATIC), * @return the pointer to the JPMethodDispatch. */ long defineMethodDispatch( long context, long cls, String name, long[] overloadList, int modifiers); // // /** * Destroy the resources. * * @param context JPContext object * @param resources * @param sz */ void destroy( long context, long[] resources, int sz); // } jpype-1.3.0/native/java/org/jpype/manager/TypeFactoryNative.java000066400000000000000000000051571405671516700247100ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype.manager; import java.lang.reflect.Executable; import java.lang.reflect.Field; /** * This is the interface for creating C++ object in JPype. *

* These methods are all native. *

*/ public class TypeFactoryNative implements TypeFactory { public long context; public native void newWrapper(long context, long cls); @Override public native long defineArrayClass( long context, Class cls, String name, long superClass, long componentPtr, int modifiers); @Override public native long defineObjectClass( long context, Class cls, String name, long superClass, long[] interfaces, int modifiers); @Override public native long definePrimitive( long context, String name, Class cls, long boxedPtr, int modifiers); @Override public native void assignMembers( long context, long cls, long ctorMethod, long[] methodList, long[] fieldList); @Override public native long defineField( long context, long cls, String name, Field field, long fieldType, int modifiers); @Override public native long defineMethod( long context, long cls, String name, Executable method, long[] overloadList, int modifiers); @Override public native void populateMethod( long context, long method, long returnType, long[] argumentTypes); @Override public native long defineMethodDispatch( long context, long cls, String name, long[] overloadList, int modifiers); @Override public native void destroy( long context, long[] resources, int sz); } jpype-1.3.0/native/java/org/jpype/manager/TypeManager.java000066400000000000000000000666041405671516700235100ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype.manager; import java.io.Serializable; import java.lang.annotation.Annotation; import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.Executable; import java.lang.reflect.Field; import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Proxy; import java.util.Arrays; import java.nio.Buffer; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.TreeSet; import org.jpype.JPypeContext; import org.jpype.proxy.JPypeProxy; /** * */ public class TypeManager { public long context = 0; public boolean isStarted = false; public boolean isShutdown = false; public HashMap classMap = new HashMap<>(); public TypeFactory typeFactory = null; public TypeAudit audit = null; private ClassDescriptor java_lang_Object; public Class functionalAnnotation = null; // For reasons that are less than clear, this object cannot be created // during shutdown private Destroyer destroyer = new Destroyer(); public TypeManager() { } public TypeManager(long context, TypeFactory typeFactory) { this.context = context; this.typeFactory = typeFactory; } // public synchronized void init() { try { if (isStarted) throw new RuntimeException("Cannot be restarted"); isStarted = true; isShutdown = false; try { this.functionalAnnotation = Class.forName("java.lang.FunctionalInterface") .asSubclass(Annotation.class); } catch (ClassNotFoundException ex) { // It is okay if we don't find this } // Create the required minimum classes this.java_lang_Object = createClass(Object.class, true); // Note that order is very important when creating these initial wrapper // types. If something inherits from another type then the super class // will be created without the special flag and the type system won't // be able to handle the duplicate type properly. Class[] cls = { Class.class, Number.class, CharSequence.class, Throwable.class, Void.class, Boolean.class, Byte.class, Character.class, Short.class, Integer.class, Long.class, Float.class, Double.class, String.class, JPypeProxy.class, Method.class, Field.class }; for (Class c : cls) { createClass(c, true); } // Create the primitive types // Link boxed and primitive types so that the wrappers can find them. createPrimitive("void", Void.TYPE, Void.class); createPrimitive("boolean", Boolean.TYPE, Boolean.class); createPrimitive("byte", Byte.TYPE, Byte.class); createPrimitive("char", Character.TYPE, Character.class); createPrimitive("short", Short.TYPE, Short.class); createPrimitive("int", Integer.TYPE, Integer.class); createPrimitive("long", Long.TYPE, Long.class); createPrimitive("float", Float.TYPE, Float.class); createPrimitive("double", Double.TYPE, Double.class); } catch (Throwable ex) { // We can't get debugging information at this point in the process. ex.printStackTrace(); throw ex; } } /** * Find a wrapper for a class. *

* Creates one if needed. This a front end used by JPype. * * @param cls * @return the JPClass, or 0 it one cannot be created. */ public synchronized long findClass(Class cls) { if (cls == null) return 0; if (this.isShutdown) return 0; long out; if (cls.isSynthetic() && cls.getSimpleName().contains("$Lambda$")) { // If is it lambda, we need a special wrapper // we don't want to create a class each time in that case. // Thus use the parent interface for this class out = getClass(cls.getInterfaces()[0]).classPtr; } else if (cls.isAnonymousClass()) { // This one is more of a burden. It depends what whether is was // anonymous extends or implements. if (cls.getInterfaces().length == 1) out = getClass(cls.getInterfaces()[0]).classPtr; else { ClassDescriptor parent = getClass(cls.getSuperclass()); out = createAnonymous(parent); } } else { // Just a regular class out = getClass(cls).classPtr; } return out; } /** * Get a class by name. * * @param name is the class name. * @return the C++ portion. */ public long findClassByName(String name) { Class cls = lookupByName(name); if (cls == null) return 0; return this.findClass(cls); } public Class lookupByName(String name) { ClassLoader classLoader = JPypeContext.getInstance().getClassLoader(); // Handle arrays if (name.endsWith("[]")) { int dims = 0; while (name.endsWith("[]")) { dims++; name = name.substring(0, name.length() - 2); } Class cls = lookupByName(name); if (cls == null) return null; return Array.newInstance(cls, new int[dims]).getClass(); } try { // Attempt direct lookup return Class.forName(name, true, classLoader); } catch (ClassNotFoundException ex) { } // Deal with JNI style names if (name.contains("/")) { try { return Class.forName(name.replaceAll("/", "."), true, classLoader); } catch (ClassNotFoundException ex) { } } // Special case for primitives if (!name.contains(".")) { if ("boolean".equals(name)) return Boolean.TYPE; if ("byte".equals(name)) return Byte.TYPE; if ("char".equals(name)) return Character.TYPE; if ("short".equals(name)) return Short.TYPE; if ("long".equals(name)) return Long.TYPE; if ("int".equals(name)) return Integer.TYPE; if ("float".equals(name)) return Float.TYPE; if ("double".equals(name)) return Double.TYPE; } // Attempt to find an inner class String[] parts = name.split("\\."); StringBuilder sb = new StringBuilder(); sb.append(parts[0]); for (int i = 1; i < parts.length; ++i) { try { sb.append("."); sb.append(parts[i]); Class cls = Class.forName(sb.toString()); for (int j = i + 1; j < parts.length; ++j) { sb.append("$"); sb.append(parts[j]); } return Class.forName(sb.toString()); } catch (ClassNotFoundException ex) { } } return null; } public synchronized void populateMethod(long wrapper, Executable method) { if (method == null) return; long returnType = 0; if (method instanceof Method) { returnType = getClass(((Method) method).getReturnType()).classPtr; } Class[] params = method.getParameterTypes(); int i = 0; long[] paramPtrs; if (!Modifier.isStatic(method.getModifiers()) && !(method instanceof Constructor)) { paramPtrs = new long[params.length + 1]; paramPtrs[0] = getClass(method.getDeclaringClass()).classPtr; i++; } else { paramPtrs = new long[params.length]; } // Copy in the parameters for (Class p : params) { paramPtrs[i] = getClass(p).classPtr; i++; } try { typeFactory.populateMethod(context, wrapper, returnType, paramPtrs); } catch (Exception ex) { ex.printStackTrace(); } } /** * Get a class for an object. * * @param object is the object to interrogate. * @return the C++ portion or null if the object is null. * @throws java.lang.InterruptedException */ public long findClassForObject(Object object) throws InterruptedException { JPypeContext.clearInterrupt(true); if (object == null) return 0; Class cls = object.getClass(); if (Proxy.isProxyClass(cls) && (Proxy.getInvocationHandler(object) instanceof JPypeProxy)) { return this.findClass(JPypeProxy.class); } return this.findClass(cls); } /** * Called to delete all C++ resources */ public synchronized void shutdown() { // First and most important, we can't operate from this // point forward. this.isShutdown = true; // Destroy all the resources held in C++ for (ClassDescriptor entry : this.classMap.values()) { destroyer.add(entry.constructorDispatch); destroyer.add(entry.constructors); destroyer.add(entry.methodDispatch); destroyer.add(entry.methods); destroyer.add(entry.fields); destroyer.add(entry.anonymous); destroyer.add(entry.classPtr); // The same wrapper can appear more than once so blank as we go. entry.constructorDispatch = 0; entry.constructors = null; entry.methodDispatch = null; entry.methods = null; entry.fields = null; entry.anonymous = 0; entry.classPtr = 0; } destroyer.flush(); // FIXME. If someone attempts to shutdown the JVM within a Python // proxy, everything will crash here. We would lose the class // that is calling things and the ability to throw exceptions. // Most likely this will go splat. We need to catch this // from within JPype and hard fault our way to safety. this.classMap.clear(); } // // private ClassDescriptor getClass(Class cls) { if (cls == null) return null; // Look up the current description ClassDescriptor ptr = this.classMap.get(cls); if (ptr != null) return ptr; // If we can't find it create a new class return createClass(cls, false); } /** * Allocate a new wrapper for a java class. *

* Boxed types require special handlers, as does java.lang.String * * @param cls is the Java class to wrap. * @param special marks class as requiring a specialized C++ wrapper. * @return a C++ wrapper handle for a jp_classtype */ private ClassDescriptor createClass(Class cls, boolean special) { if (cls.isArray()) return this.createArrayClass(cls); return createOrdinaryClass(cls, special, true); } private ClassDescriptor createOrdinaryClass(Class cls, boolean special, boolean bases) { // Verify the class will be loadable prior to creating the class. // If we fail to do this then the class may end up crashing later when the // members get populated which could leave us in a bad state. cls.getMethods(); cls.getFields(); // Object classes are more work as we need the super information as well. // Make sure all base classes are loaded Class superClass = cls.getSuperclass(); Class[] interfaces = cls.getInterfaces(); ClassDescriptor[] parents = new ClassDescriptor[interfaces.length + 1]; long[] interfacesPtr = null; long superClassPtr = 0; superClassPtr = 0; if (superClass != null) { parents[0] = this.getClass(superClass); superClassPtr = parents[0].classPtr; } if (bases) { interfacesPtr = new long[interfaces.length]; // Make sure all interfaces are loaded. for (int i = 0; i < interfaces.length; ++i) { parents[i + 1] = this.getClass(interfaces[i]); interfacesPtr[i] = parents[i + 1].classPtr; } } else { interfacesPtr = new long[0]; } // Set up the modifiers int modifiers = cls.getModifiers() & 0xffff; if (special) modifiers |= ModifierCode.SPECIAL.value; if (Throwable.class.isAssignableFrom(cls)) modifiers |= ModifierCode.THROWABLE.value; if (Serializable.class.isAssignableFrom(cls)) modifiers |= ModifierCode.SERIALIZABLE.value; if (Arrays.asList(cls.getInterfaces()).contains(Comparable.class)) modifiers |= ModifierCode.COMPARABLE.value; if (Buffer.class.isAssignableFrom(cls)) modifiers |= ModifierCode.BUFFER.value | ModifierCode.SPECIAL.value; if (this.functionalAnnotation != null && cls.getAnnotation(this.functionalAnnotation) != null) modifiers |= ModifierCode.FUNCTIONAL.value | ModifierCode.SPECIAL.value; // FIXME watch out for anonyous and lambda here. String name = cls.getCanonicalName(); if (name == null) name = cls.getName(); // Create the JPClass long classPtr = typeFactory.defineObjectClass(context, cls, name, superClassPtr, interfacesPtr, modifiers); // Cache the wrapper. ClassDescriptor out = new ClassDescriptor(cls, classPtr); this.classMap.put(cls, out); return out; } private long createAnonymous(ClassDescriptor parent) { if (parent.anonymous != 0) return parent.anonymous; parent.anonymous = typeFactory.defineObjectClass(context, parent.cls, parent.cls.getCanonicalName() + "$Anonymous", parent.classPtr, null, ModifierCode.ANONYMOUS.value); return parent.anonymous; } ClassDescriptor createArrayClass(Class cls) { // Array classes are simple, we just need the component type Class componentType = cls.getComponentType(); long componentTypePtr = this.getClass(componentType).classPtr; int modifiers = cls.getModifiers() & 0xffff; String name = cls.getName(); if (!name.endsWith(";")) modifiers |= ModifierCode.PRIMITIVE_ARRAY.value; long classPtr = typeFactory .defineArrayClass(context, cls, cls.getCanonicalName(), this.java_lang_Object.classPtr, componentTypePtr, modifiers); ClassDescriptor out = new ClassDescriptor(cls, classPtr); this.classMap.put(cls, out); return out; } /** * Tell JPype to make a primitive Class. * * @param name * @param cls * @param boxed */ private void createPrimitive(String name, Class cls, Class boxed) { long classPtr = typeFactory.definePrimitive(context, name, cls, this.getClass(boxed).classPtr, cls.getModifiers() & 0xffff); this.classMap.put(cls, new ClassDescriptor(cls, classPtr)); } // // public synchronized void populateMembers(Class cls) { ClassDescriptor desc = this.classMap.get(cls); if (desc == null) throw new RuntimeException("Class not loaded"); if (desc.fields != null) return; try { createMembers(desc); } catch (Exception ex) { ex.printStackTrace(System.out); throw ex; } } private void createMembers(ClassDescriptor desc) { this.createFields(desc); this.createConstructorDispatch(desc); this.createMethodDispatches(desc); // Verify integrity if (audit != null) audit.verifyMembers(desc); // Pass this to JPype this.typeFactory.assignMembers(context, desc.classPtr, desc.constructorDispatch, desc.methodDispatch, desc.fields); } // private void createFields(ClassDescriptor desc) { // We only need declared fields as the wrappers for previous classes hold // members declared earlier LinkedList fields = filterPublic(desc.cls.getDeclaredFields()); long[] fieldPtr = new long[fields.size()]; int i = 0; for (Field field : fields) { fieldPtr[i++] = this.typeFactory.defineField(context, desc.classPtr, field.getName(), field, getClass(field.getType()).classPtr, field.getModifiers() & 0xffff); } desc.fields = fieldPtr; } // // /** * Load the constructors for a class. * * @param desc */ public void createConstructorDispatch(ClassDescriptor desc) { Class cls = desc.cls; // Get the list of declared constructors LinkedList constructors = filterPublic(cls.getDeclaredConstructors()); if (constructors.isEmpty()) return; // Sort them by precedence order List overloads = MethodResolution.sortMethods(constructors); // Convert overload list to a list of overloads pointers desc.constructors = this.createConstructors(desc, overloads); // Create the dispatch for it desc.constructorDispatch = typeFactory .defineMethodDispatch(context, desc.classPtr, "", desc.constructors, ModifierCode.PUBLIC.value | ModifierCode.CTOR.value); } /** * Construct a set of constructor overloads for an OverloadResolution. *

* These will be added to the shutdown destruction list. * * @param desc * @param overloads * @return */ private long[] createConstructors(ClassDescriptor desc, List overloads) { int n = overloads.size(); long[] overloadPtrs = new long[overloads.size()]; for (MethodResolution ov : overloads) { Constructor constructor = (Constructor) ov.executable; int i = 0; long[] precedencePtrs = new long[ov.children.size()]; for (MethodResolution ch : ov.children) { precedencePtrs[i++] = ch.ptr; } int modifiers = constructor.getModifiers() & 0xffff; modifiers |= ModifierCode.CTOR.value; ov.ptr = typeFactory.defineMethod(context, desc.classPtr, constructor.toString(), constructor, precedencePtrs, modifiers); overloadPtrs[--n] = ov.ptr; } return overloadPtrs; } // // /** * Load the methods for a class. * * @param desc */ public void createMethodDispatches(ClassDescriptor desc) { Class cls = desc.cls; // Get the list of all public, non-overrided methods we will process LinkedList methods = filterOverridden(cls, cls.getMethods()); // Get the list of public declared methods LinkedList declaredMethods = filterOverridden(cls, cls.getDeclaredMethods()); // We only need one dispatch per name TreeSet resolve = new TreeSet<>(); for (Method method : declaredMethods) { resolve.add(method.getName()); } // Reserve memory for our lookup table desc.methods = new long[declaredMethods.size()]; desc.methodIndex = new Method[declaredMethods.size()]; desc.methodDispatch = new long[resolve.size()]; int i = 0; for (String name : resolve) { desc.methodDispatch[i++] = this.createMethodDispatch(desc, name, methods); } } private long createMethodDispatch( ClassDescriptor desc, String key, LinkedList candidates) { // Find all the methods that match the key LinkedList methods = new LinkedList<>(); Iterator iter = candidates.iterator(); int modifiers = 0; while (iter.hasNext()) { Method next = iter.next(); if (!next.getName().equals(key)) continue; iter.remove(); methods.add(next); if (Modifier.isStatic(next.getModifiers())) modifiers |= ModifierCode.STATIC.value; if (isBeanAccessor(next)) modifiers |= ModifierCode.BEAN_ACCESSOR.value; if (isBeanMutator(next)) modifiers |= ModifierCode.BEAN_MUTATOR.value; } // Convert overload list to a list of overloads pointers List overloads = MethodResolution.sortMethods(methods); long[] overloadPtrs = this.createMethods(desc, overloads); long methodContainer = typeFactory.defineMethodDispatch(context, desc.classPtr, key, overloadPtrs, modifiers); return methodContainer; } /** * Convert a list of executable overload resolutions into a executable * overload list. *

* These will be added to the shutdown destruction list. * * @param desc * @param overloads * @return a list of method overload wrappers. */ private long[] createMethods( ClassDescriptor desc, List overloads) { int n = overloads.size(); long[] overloadPtrs = new long[overloads.size()]; for (MethodResolution ov : overloads) { Method method = (Method) ov.executable; // We may already have built a methodoverload for this Class decl = method.getDeclaringClass(); if (method.getDeclaringClass() != desc.cls) { this.populateMembers(decl); ov.ptr = this.classMap.get(decl).getMethod(method); if (ov.ptr == 0) { if (audit != null) audit.failFindMethod(desc, method); throw new RuntimeException("Fail"); } overloadPtrs[--n] = ov.ptr; continue; } // Determine what takes precedence int i = 0; long[] precedencePtrs = new long[ov.children.size()]; for (MethodResolution ch : ov.children) { precedencePtrs[i++] = ch.ptr; } int modifiers = method.getModifiers() & 0xffff; if (isBeanMutator(method)) modifiers |= ModifierCode.BEAN_MUTATOR.value; if (isBeanAccessor(method)) modifiers |= ModifierCode.BEAN_ACCESSOR.value; if (isCallerSensitive(method)) modifiers |= ModifierCode.CALLER_SENSITIVE.value; ov.ptr = typeFactory.defineMethod(context, desc.classPtr, method.toString(), method, precedencePtrs, modifiers); overloadPtrs[--n] = ov.ptr; desc.methods[desc.methodCounter] = ov.ptr; desc.methodIndex[desc.methodCounter] = method; desc.methodCounter++; } return overloadPtrs; } static boolean hasCallerSensitive = false; static { try { java.lang.reflect.Method method = java.lang.Class.class.getDeclaredMethod("forName", String.class); for (Annotation annotation : method.getAnnotations()) { if ("@jdk.internal.reflect.CallerSensitive()".equals(annotation.toString())) { hasCallerSensitive = true; } } } catch (NoSuchMethodException | SecurityException ex) { } } /** * Checks to see if the method is caller sensitive. * * As the annotation is a private internal, we must check by name. * * @param method is the method to be probed. * @return true if caller sensitive. */ public static boolean isCallerSensitive(Method method) { if (hasCallerSensitive) { for (Annotation annotation : method.getAnnotations()) { if ("@jdk.internal.reflect.CallerSensitive()".equals(annotation.toString())) { return true; } } } else { // JDK prior versions prior to 9 do not annotate methods that // require special handling, thus we will just blanket those // classes known to have issues. Class cls = method.getDeclaringClass(); if (cls.equals(java.lang.Class.class) || cls.equals(java.lang.ClassLoader.class) || cls.equals(java.sql.DriverManager.class)) { return true; } } return false; } // // // // // /** * Remove any methods that are not public from a list. * * @param * @param methods * @return a new list containing only public members. */ public static LinkedList filterPublic(T[] methods) { LinkedList out = new LinkedList<>(); for (T method : methods) { if (!Modifier.isPublic(method.getModifiers())) continue; out.add(method); } return out; } /** * Remove any methods that are not public and have been overridden from a * list. * * @param cls * @param methods * @return a new list containing only public members that are not overridden. */ public static LinkedList filterOverridden(Class cls, Method[] methods) { LinkedList out = new LinkedList<>(); for (Method method : methods) { if (!Modifier.isPublic(method.getModifiers()) || isOverridden(cls, method)) continue; out.add(method); } return out; } // // /** * Determines if a method is masked by another in a class. * * @param cls is the class to investigate. * @param method is a method that applies to the class. * @return true if the method is hidden by another method. */ public static boolean isOverridden(Class cls, Method method) { try { return !method.equals(cls.getMethod(method.getName(), method.getParameterTypes())); } catch (NoSuchMethodException | SecurityException ex) { return false; } } /** * Bean accessor is flag is used for property module. *

* Accessors need * * @param method * @return */ private boolean isBeanAccessor(Method method) { if (Modifier.isStatic(method.getModifiers())) return false; if (method.getReturnType().equals(void.class)) return false; if (method.getParameterCount() > 0) return false; if (method.getName().length() < 4) return false; return (method.getName().startsWith("get")); } /** * Bean mutator is flag is used for property module. * * @param method * @return */ private boolean isBeanMutator(Method method) { if (Modifier.isStatic(method.getModifiers())) return false; if (!method.getReturnType().equals(void.class)) return false; if (method.getParameterCount() != 1) return false; if (method.getName().length() < 4) return false; return (method.getName().startsWith("set")); } // // private class Destroyer { final int BLOCK_SIZE = 1024; long[] queue = new long[BLOCK_SIZE]; int index = 0; void add(long v) { if (v == 0) return; queue[index++] = v; if (index == BLOCK_SIZE) flush(); } void add(long[] v) { if (v == null) return; if (v.length > BLOCK_SIZE / 2) { typeFactory.destroy(context, v, v.length); return; } if (index + v.length > BLOCK_SIZE) { flush(); } for (int j = 0; j < v.length; ++j) { queue[index++] = v[j]; } if (index == BLOCK_SIZE) flush(); } void flush() { typeFactory.destroy(context, queue, index); index = 0; } } // } jpype-1.3.0/native/java/org/jpype/pickle/000077500000000000000000000000001405671516700202525ustar00rootroot00000000000000jpype-1.3.0/native/java/org/jpype/pickle/ByteBufferInputStream.java000066400000000000000000000047131405671516700253530ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype.pickle; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; /** * * @author Karl Einar Nelson */ public class ByteBufferInputStream extends InputStream { ByteBuffer bb = ByteBuffer.allocate(1024); int loaded = 0; public void put(byte[] bytes) { // If we have additional capacity, use it if (bytes.length < bb.remaining()) { int p = bb.position(); bb.position(loaded); bb.put(bytes); loaded = bb.position(); bb.position(p); return; } // Okay we may need to allocate more ByteBuffer bb2 = bb; int r = loaded - bb.position(); // If we don't have space, make a new buffer. if (r + bytes.length > bb.capacity()) bb = ByteBuffer.allocate(r + bytes.length); // If we have remaining bytes, then keep them if (r > 0) { bb.put(bb2.array(), bb2.position(), r); } // Add the new data bb.put(bytes); loaded = bb.position(); bb.position(0); } public int available() { int out = loaded - bb.position(); return out; } @Override public int read() throws IOException { int r = loaded - bb.position(); if (r > 0) { int p = bb.get(); return p; } return -1; } @Override public int read(byte[] arg0) throws IOException { int r = loaded - bb.position(); if (arg0.length <= r) { bb.get(arg0); return arg0.length; } bb.get(arg0, 0, r); return r; } @Override public int read(byte[] buffer, int offset, int len) throws IOException { int r = loaded - bb.position(); if (r == 0) return -1; if (len > r) { len = r; } bb.get(buffer, offset, len); return len; } } jpype-1.3.0/native/java/org/jpype/pickle/Decoder.java000066400000000000000000000022471405671516700224670ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype.pickle; import java.io.IOException; import java.io.ObjectInputStream; public class Decoder { ByteBufferInputStream bb; ObjectInputStream ois = null; public Decoder() throws IOException { bb = new ByteBufferInputStream(); } public Object unpack(byte[] data) throws IOException, ClassNotFoundException { bb.put(data); if (ois == null) ois = new ObjectInputStream(bb); return ois.readObject(); } } jpype-1.3.0/native/java/org/jpype/pickle/Encoder.java000066400000000000000000000024201405671516700224720ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype.pickle; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; /** * * @author Karl Einar Nelson */ public class Encoder { ByteArrayOutputStream baos; ObjectOutputStream oos; public Encoder() throws IOException { baos = new ByteArrayOutputStream(); oos = new ObjectOutputStream(baos); } public byte[] pack(Object obj) throws IOException { oos.writeObject(obj); oos.flush(); byte[] out = baos.toByteArray().clone(); baos.reset(); return out; } } jpype-1.3.0/native/java/org/jpype/pkg/000077500000000000000000000000001405671516700175645ustar00rootroot00000000000000jpype-1.3.0/native/java/org/jpype/pkg/JPypePackage.java000066400000000000000000000167551405671516700227500ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype.pkg; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Modifier; import java.net.URI; import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.Map; import org.jpype.JPypeContext; import org.jpype.JPypeKeywords; import org.jpype.classloader.DynamicClassLoader; /** * Representation of a JPackage in Java. * * This provides the dir and attributes for a JPackage and by extension jpype * imports. Almost all of the actual work happens in the PackageManager which * acts like the classloader to figure out what resource are available. * */ public class JPypePackage { // Name of the package final String pkg; // A mapping from Python names into Paths into the module/jar file system. Map contents; int code; private final DynamicClassLoader classLoader; public JPypePackage(String pkg) { this.pkg = pkg; this.contents = JPypePackageManager.getContentMap(pkg); this.classLoader = ((DynamicClassLoader)(JPypeContext.getInstance().getClassLoader())); this.code = classLoader.getCode(); } /** * Get an object from the package. * * This is used by the importer to create the attributes for `getattro`. The * type returned is polymorphic. We can potentially support any type of * resource (package, classes, property files, xml, data, etc). But for now we * are primarily interested in packages and classes. Packages are returned as * strings as loading the package info is not guaranteed to work. Classes are * returned as classes which are immediately converted into Python wrappers. * We can return other resource types so long as they have either a wrapper * type to place the instance into an Python object directly or a magic * wrapper which will load the resource into a Python object type. * * This should match the acceptable types in getContents so that everything in * the `dir` is also an attribute of JPackage. * * @param name is the name of the resource. * @return the object or null if no resource is found with a matching name. */ public Object getObject(String name) { // We can't use the url contents as the contents may be incomplete due // to bugs in the JVM classloaders. Instead we will have to probe. String basename = pkg + "." + JPypeKeywords.unwrap(name); ClassLoader cl = JPypeContext.getInstance().getClassLoader(); try { // Check if it a package if (JPypePackageManager.isPackage(basename)) { return basename; } // Else probe for a class. Class cls = Class.forName(basename, false, JPypeContext.getInstance().getClassLoader()); if (Modifier.isPublic(cls.getModifiers())) return Class.forName(basename, true, cl); } catch (ClassNotFoundException ex) { // Continue } return null; } /** * Get a list of contents from a Java package. * * This will be used when creating the package `dir` * * @return */ public String[] getContents() { checkCache(); ArrayList out = new ArrayList<>(); for (String key : contents.keySet()) { URI uri = contents.get(key); // If there is anything null, then skip it. if (uri == null) continue; Path p = JPypePackageManager.getPath(uri); // package are acceptable if (Files.isDirectory(p)) out.add(key); // classes must be public else if (uri.toString().endsWith(".class")) { // Make sure it is public if (isPublic(p)) out.add(key); } } return out.toArray(new String[out.size()]); } /** * Determine if a class is public. * * This checks if a class file contains a public class. When importing classes * we do not want to instantiate a class which is not public as it may result * in instantiation of static variables or unwanted class resources. The only * alternative is to read the class file and get the class modifier flags. * Unfortunately, the developers of Java were rather stingy on their byte * allocation and thus the field we want is not in the header but rather * buried after the constant pool. Further as they didn't give the actual size * of the tables in bytes, but rather in entries, that means we have to parse * the whole table just to get the access flags after it. * * @param p * @return */ static boolean isPublic(Path p) { try (InputStream is = Files.newInputStream(p)) { // Allocate a three byte buffer for traversing the constant pool. // The minumum entry is a byte for the type and 2 data bytes. We // will read these three bytes and then based on the type advance // the read pointer to the next entry. ByteBuffer buffer3 = ByteBuffer.allocate(3); // Check the magic ByteBuffer header = ByteBuffer.allocate(4 + 2 + 2 + 2); is.read(header.array()); ((Buffer) header).rewind(); int magic = header.getInt(); if (magic != (int) 0xcafebabe) return false; header.getShort(); // skip major header.getShort(); // skip minor short cpitems = header.getShort(); // get the number of items // Traverse the cp pool for (int i = 0; i < cpitems - 1; ++i) { is.read(buffer3.array()); ((Buffer) buffer3).rewind(); byte type = buffer3.get(); // First byte is the type // Now based on the entry type we will advance the pointer switch (type) { case 1: // Strings are variable length is.skip(buffer3.getShort()); break; case 7: case 8: case 16: case 19: case 20: break; case 15: is.skip(1); break; case 3: case 4: case 9: case 10: case 11: case 12: case 17: case 18: is.skip(2); break; case 5: case 6: is.skip(6); // double and long are special as they are double entries i++; // long and double take two slots break; default: return false; } } // Get the flags is.read(buffer3.array()); ((Buffer) buffer3).rewind(); short flags = buffer3.getShort(); return (flags & 1) == 1; // it is public if bit zero is set } catch (IOException ex) { return false; // If anything goes wrong then it won't be considered a public class. } } void checkCache() { int current = classLoader.getCode(); if (this.code == current) return; this.code = current; this.contents = JPypePackageManager.getContentMap(pkg); } } jpype-1.3.0/native/java/org/jpype/pkg/JPypePackageManager.java000066400000000000000000000331261405671516700242320ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype.pkg; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.nio.file.FileSystem; import java.nio.file.FileSystemNotFoundException; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.ProviderNotFoundException; import java.nio.file.spi.FileSystemProvider; import java.util.ArrayList; import java.util.Arrays; import java.util.Enumeration; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.jpype.JPypeContext; import org.jpype.JPypeKeywords; /** * Manager for the contents of a package. * * This class uses a number of tricks to provide a way to determine what * packages are available in the class loader. It searches the jar path, the * boot path (Java 8), and the module path (Java 9+). It does not currently work * with alternative classloaders. This class was rumored to be unobtainium as * endless posts indicated that it wasn't possible to determine the contents of * a package in general nor to retrieve the package contents, but this appears * to be largely incorrect as the jar and jrt file system provide all the * required methods. * */ public class JPypePackageManager { final static List bases = new ArrayList(); final static List modules = getModules(); final static FileSystemProvider jfsp = getFileSystemProvider("jar"); final static Map env = new HashMap<>(); final static LinkedList fs = new LinkedList<>(); /** * Checks if a package exists. * * @param name is the name of the package. * @return true if this is a Java package either in a jar, module, or in the * boot path. */ public static boolean isPackage(String name) { if (name.indexOf('.') != -1) name = name.replace(".", "/"); if (isModulePackage(name) || isBasePackage(name) || isJarPackage(name)) return true; return false; } /** * Get the list of the contents of a package. * * @param packageName * @return the list of all resources found. */ public static Map getContentMap(String packageName) { Map out = new HashMap<>(); packageName = packageName.replace(".", "/"); // We need to merge all the file systems into one view like the classloader getJarContents(out, packageName); getBaseContents(out, packageName); getModuleContents(out, packageName); return out; } /** * Convert a URI into a path. * * This has special magic methods to deal with jar file systems. * * @param uri is the location of the resource. * @return the path to the uri resource. */ static Path getPath(URI uri) { try { return Paths.get(uri); } catch (java.nio.file.FileSystemNotFoundException ex) { } if (uri.getScheme().equals("jar")) { try { // Limit the number of filesystems open at any one time fs.add(jfsp.newFileSystem(uri, env)); if (fs.size() > 8) fs.removeFirst().close(); return Paths.get(uri); } catch (IOException ex) { } } throw new FileSystemNotFoundException("Unknown filesystem for " + uri); } /** * Retrieve the Jar file system. * * @return */ private static FileSystemProvider getFileSystemProvider(String str) { for (FileSystemProvider fsp : FileSystemProvider.installedProviders()) { if (fsp.getScheme().equals(str)) return fsp; } throw new FileSystemNotFoundException("Unable to find filesystem for " + str); } // /** * Older versions of Java do not have a file system for boot packages. Thus * rather working through the classloader, we will instead probe java to get * the rt.jar. Crypto is a special case as it has its own jar. All other * resources are sourced through the regular jar loading method. */ static { env.put("create", "true"); ClassLoader cl = ClassLoader.getSystemClassLoader(); URI uri = null; try { // This is for Java 8 and earlier in which the API jars are in rt.jar // and jce.jar uri = cl.getResource("java/lang/String.class").toURI(); if (uri != null && uri.getScheme().equals("jar")) { FileSystem fs = jfsp.newFileSystem(uri, env); if (fs != null) bases.add(fs); } uri = cl.getResource("javax/crypto/Cipher.class").toURI(); if (uri != null && uri.getScheme().equals("jar")) { FileSystem fs = jfsp.newFileSystem(uri, env); if (fs != null) bases.add(fs); } } catch (URISyntaxException | IOException ex) { } } private static void getBaseContents(Map out, String packageName) { for (FileSystem b : bases) { collectContents(out, b.getPath(packageName)); } } /** * Check if a name is a package in the java bootstrap classloader. * * @param name * @return */ private static boolean isBasePackage(String name) { try { if (name.isEmpty()) return false; for (FileSystem jar : bases) { if (Files.isDirectory(jar.getPath(name))) return true; } return false; } catch (Exception ex) { throw new RuntimeException("Fail checking package '" + name + "'", ex); } } // // /** * Get a list of all modules. * * This may be many modules or just a few. Limited distributes created using * jlink will only have a portion of the usual modules. * * @return */ static List getModules() { ArrayList out = new ArrayList<>(); try { FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); Path modulePath = fs.getPath("modules"); for (Path module : Files.newDirectoryStream(modulePath)) { out.add(new ModuleDirectory(module)); } } catch (ProviderNotFoundException | IOException ex) { } return out; } /** * Check if a name corresponds to a package in a module. * * @param name * @return true if it is a package. */ private static boolean isModulePackage(String name) { if (modules.isEmpty()) return false; String[] split = name.split("/"); String search = name; if (split.length > 3) search = String.join("/", Arrays.copyOfRange(split, 0, 3)); for (ModuleDirectory module : modules) { if (module.contains(search)) { if (Files.isDirectory(module.modulePath.resolve(name))) return true; } } return false; } /** * Retrieve the contents of a module by package name. * * @param out * @param name */ private static void getModuleContents(Map out, String name) { if (modules.isEmpty()) return; String[] split = name.split("/"); String search = name; if (split.length > 3) search = String.join("/", Arrays.copyOfRange(split, 0, 3)); for (ModuleDirectory module : modules) { if (module.contains(search)) { Path path2 = module.modulePath.resolve(name); if (Files.isDirectory(path2)) collectContents(out, path2); } } } /** * Modules are stored in the jrt filesystem. * * However, that is not a simple flat filesystem by path as the jrt files are * structured by package name. Thus we will need a separate structure which is * rooted at the top of each module. */ private static class ModuleDirectory { List contents = new ArrayList<>(); private final Path modulePath; ModuleDirectory(Path module) { this.modulePath = module; listPackages(contents, module, module, 0); } boolean contains(String path) { for (String s : contents) { if (s.equals(path)) return true; } return false; } private static void listPackages(List o, Path base, Path p, int depth) { try { if (depth >= 3) return; for (Path d : Files.newDirectoryStream(p)) { if (Files.isDirectory(d)) { o.add(base.relativize(d).toString()); listPackages(o, base, d, depth + 1); } } } catch (IOException ex) { } } } // // /** * Checks if a name corresponds to package in a jar file or on the classpath * filesystem. * * Classloaders provide a method to get all resources with a given name. This * is needed because the same package name may appear in multiple jars or * filesystems. We do not need to disambiguate it here, but just get a listing * that we can use to find a resource later. * * @param name is the name of the package to search for. * @return true if the name corresponds to a Java package. */ private static boolean isJarPackage(String name) { ClassLoader cl = JPypeContext.getInstance().getClassLoader(); try { Enumeration resources = cl.getResources(name); while (resources.hasMoreElements()) { URI uri = resources.nextElement().toURI(); if (Files.isDirectory(getPath(uri))) return true; } } catch (IOException | URISyntaxException ex) { } return false; } /** * Retrieve a list of packages and classes stored on a file system or in a * jar. * * @param out is the map to store the result in. * @param packageName is the name of the package */ private static void getJarContents(Map out, String packageName) { ClassLoader cl = JPypeContext.getInstance().getClassLoader(); try { String path = packageName.replace('.', '/'); Enumeration resources = cl.getResources(path); while (resources.hasMoreElements()) { URI resource = resources.nextElement().toURI(); // Handle MRJAR format // MRJAR may not report every directory but instead just the overlay. // So we need to find the original and interogate it first before // checking the version specific part. Worst case we collect the // contents twice. String schemePart = resource.getSchemeSpecificPart(); int index = schemePart.indexOf("!"); if (index != -1) { if (schemePart.substring(index + 1).startsWith("/META-INF/versions/")) { int index2 = schemePart.indexOf('/', index + 20); schemePart = schemePart.substring(0, index + 1) + schemePart.substring(index2); URI resource2 = new URI(resource.getScheme() + ":" + schemePart); Path path3 = getPath(resource2); collectContents(out, path3); } } Path path2 = getPath(resource); collectContents(out, path2); } } catch (IOException | URISyntaxException ex) { } } // // /** * Collect the contents from a path. * * This operates on jars, modules, and filesystems to collect the names of all * resources found. We skip over inner classes as those are accessed under * their included classes. For now we are not screening against other private * symbols. * * @param out is the map to store the result in. * @param path2 is a path holding a directory to probe. */ private static void collectContents(Map out, Path path2) { try { for (Path file : Files.newDirectoryStream(path2)) { String filename = file.getFileName().toString(); if (Files.isDirectory(file)) { // Same implementations add the path separator to the end of toString(). if (filename.endsWith(file.getFileSystem().getSeparator())) filename = filename.substring(0, filename.length() - 1); out.put(JPypeKeywords.wrap(filename), toURI(file)); continue; } // Skip inner classes if (filename.contains("$")) continue; // Include class files if (filename.endsWith(".class")) { String key = JPypeKeywords.wrap(filename.substring(0, filename.length() - 6)); out.put(key, toURI(file)); } // We can add other types of files here and import them in JPypePackage // as required. } } catch (IOException ex) { } } // Java 8 windows bug https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8131067 private static URI toURI(Path path) { URI uri = path.toUri(); if (uri.getScheme().equals("jar") && uri.toString().contains("%2520")) uri = URI.create("jar:" + uri.getRawSchemeSpecificPart().replaceAll("%25", "%")); return uri; } // } jpype-1.3.0/native/java/org/jpype/proxy/000077500000000000000000000000001405671516700201645ustar00rootroot00000000000000jpype-1.3.0/native/java/org/jpype/proxy/JPypeProxy.java000066400000000000000000000063761405671516700231340ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import org.jpype.JPypeContext; import org.jpype.manager.TypeManager; import org.jpype.ref.JPypeReferenceQueue; /** * * @author Karl Einar Nelson */ public class JPypeProxy implements InvocationHandler { private final static JPypeReferenceQueue referenceQueue = JPypeReferenceQueue.getInstance(); JPypeContext context; public long instance; public long cleanup; Class[] interfaces; ClassLoader cl = ClassLoader.getSystemClassLoader(); public static JPypeProxy newProxy(JPypeContext context, long instance, long cleanup, Class[] interfaces) { JPypeProxy proxy = new JPypeProxy(); proxy.context = context; proxy.instance = instance; proxy.interfaces = interfaces; proxy.cleanup = cleanup; // Proxies must point to the correct class loader. For most cases the // system classloader is find. But if the class is in a custom classloader // we need to use that one instead for (Class cls : interfaces) { ClassLoader icl = cls.getClassLoader(); if (icl != null && icl != proxy.cl) proxy.cl = icl; } return proxy; } public Object newInstance() { Object out = Proxy.newProxyInstance(cl, interfaces, this); referenceQueue.registerRef(out, instance, cleanup); return out; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { // context.incrementProxy(); if (context.isShutdown()) throw new RuntimeException("Proxy called during shutdown"); // We can save a lot of effort on the C++ side by doing all the // type lookup work here. TypeManager typeManager = context.getTypeManager(); long returnType; long[] parameterTypes; synchronized (typeManager) { returnType = typeManager.findClass(method.getReturnType()); Class[] types = method.getParameterTypes(); parameterTypes = new long[types.length]; for (int i = 0; i < types.length; ++i) { parameterTypes[i] = typeManager.findClass(types[i]); } } return hostInvoke(context.getContext(), method.getName(), instance, returnType, parameterTypes, args); } finally { // context.decrementProxy(); } } private static native Object hostInvoke(long context, String name, long pyObject, long returnType, long[] argsTypes, Object[] args); } jpype-1.3.0/native/java/org/jpype/ref/000077500000000000000000000000001405671516700175575ustar00rootroot00000000000000jpype-1.3.0/native/java/org/jpype/ref/JPypeReference.java000066400000000000000000000026661405671516700233020ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype.ref; import java.lang.ref.PhantomReference; import java.lang.ref.ReferenceQueue; /** * (internal) Reference to a PyObject*. */ class JPypeReference extends PhantomReference { long hostReference; long cleanup; int pool; int index; public JPypeReference(ReferenceQueue arg1, Object javaObject, long host, long cleanup) { super(javaObject, arg1); this.hostReference = host; this.cleanup = cleanup; } @Override public int hashCode() { return (int) hostReference; } @Override public boolean equals(Object arg0) { if (!(arg0 instanceof JPypeReference)) { return false; } return ((JPypeReference) arg0).hostReference == hostReference; } } jpype-1.3.0/native/java/org/jpype/ref/JPypeReferenceNative.java000066400000000000000000000011501405671516700244340ustar00rootroot00000000000000package org.jpype.ref; import java.lang.reflect.Method; /** * * @author nelson85 */ public class JPypeReferenceNative { /** * Native hook to delete a native resource. * * @param host is the address of memory in C. * @param cleanup is the address the function to cleanup the memory. */ public static native void removeHostReference(long host, long cleanup); /** * Triggered by the sentinel when a GC starts. */ public static native void wake(); /** * Initialize resources. * * @param self * @param m */ public static native void init(Object self, Method m); } jpype-1.3.0/native/java/org/jpype/ref/JPypeReferenceQueue.java000066400000000000000000000120341405671516700242750ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype.ref; import java.lang.ref.PhantomReference; import java.lang.ref.ReferenceQueue; /** * Reference queue holds the life of python objects to be as long as java items. *

* Any java class that holds a pointer into python needs to have a reference so * that python object does not go away if the references in python fall to zero. * JPype will add an extra reference to the object which is removed when the * python object dies. * * @author smenard * */ final public class JPypeReferenceQueue extends ReferenceQueue { private final static JPypeReferenceQueue INSTANCE = new JPypeReferenceQueue(); private JPypeReferenceSet hostReferences; private boolean isStopped = false; private Thread queueThread; private Object queueStopMutex = new Object(); private PhantomReference sentinel = null; public static JPypeReferenceQueue getInstance() { return INSTANCE; } private JPypeReferenceQueue() { super(); this.hostReferences = new JPypeReferenceSet(); addSentinel(); JPypeReferenceNative.removeHostReference(0, 0); try { JPypeReferenceNative.init(this, getClass().getDeclaredMethod("registerRef", Object.class, Long.TYPE, Long.TYPE)); } catch (NoSuchMethodException | SecurityException ex) { throw new RuntimeException(ex); } } /** * (internal) Binds the lifetime of a Python object to a Java object. *

* JPype adds an extra reference to a PyObject* and then calls this method to * hold that reference until the Java object is garbage collected. * * @param javaObject is the object to bind the lifespan to. * @param host is the pointer to the host object. * @param cleanup is the pointer to the function to call to delete the * resource. */ public void registerRef(Object javaObject, long host, long cleanup) { if (cleanup == 0) return; if (isStopped) { JPypeReferenceNative.removeHostReference(host, cleanup); } else { JPypeReference ref = new JPypeReference(this, javaObject, host, cleanup); hostReferences.add(ref); } } /** * Start the threading queue. */ public void start() { isStopped = false; queueThread = new Thread(new Worker(), "Python Reference Queue"); queueThread.setDaemon(true); queueThread.start(); } /** * Stops the reference queue. *

* This is called by jpype when the jvm shuts down. */ public void stop() { try { synchronized (queueStopMutex) { synchronized (this) { isStopped = true; queueThread.interrupt(); } // wait for the thread to finish ... queueStopMutex.wait(10000); } } catch (InterruptedException ex) { // who cares ... } // Empty the queue. hostReferences.flush(); } /** * Checks the status of the reference queue. * * @return true is the queue is running. */ public boolean isRunning() { return !isStopped; } /** * Get the number of items in the reference queue. * * @return the number of python resources held. */ public int getQueueSize() { return this.hostReferences.size(); } // /** * Thread to monitor the queue and delete resources. */ private class Worker implements Runnable { @Override public void run() { while (!isStopped) { try { // Check if a ref has been queued. and check if the thread has been // stopped every 0.25 seconds JPypeReference ref = (JPypeReference) remove(250); if (ref == sentinel) { addSentinel(); JPypeReferenceNative.wake(); continue; } if (ref != null) { long hostRef = ref.hostReference; long cleanup = ref.cleanup; hostReferences.remove(ref); JPypeReferenceNative.removeHostReference(hostRef, cleanup); } } catch (InterruptedException ex) { // don't know why ... don't really care ... } } synchronized (queueStopMutex) { queueStopMutex.notifyAll(); } } } final void addSentinel() { sentinel = new JPypeReference(this, new byte[0], 0, 0); } // } jpype-1.3.0/native/java/org/jpype/ref/JPypeReferenceSet.java000066400000000000000000000060611405671516700237470ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype.ref; import java.util.ArrayList; /** * * @author nelson85 */ public class JPypeReferenceSet { static final int SIZE = 256; ArrayList pools = new ArrayList<>(); Pool current; private int items; JPypeReferenceSet() { } int size() { return items; } /** * Add a reference to the set. * * This should be O(1). * * @param ref */ synchronized void add(JPypeReference ref) { if (ref.cleanup == 0) return; this.items++; if (current == null) { current = new Pool(pools.size()); pools.add(current); } if (current.add(ref)) { // It is full current = null; // Find a free pool for (Pool pool : pools) { if (pool.tail < SIZE) { current = pool; return; } } } } /** * Remove a reference from the set. * * @param ref */ synchronized void remove(JPypeReference ref) { if (ref.cleanup == 0) return; pools.get(ref.pool).remove(ref); this.items--; ref.cleanup = 0; ref.pool = -1; } /** * Release all resources. * * This is triggered by shutdown to release an current Python references that * are being held. * */ void flush() { for (Pool pool : pools) { for (int i = 0; i < pool.tail; ++i) { JPypeReference ref = pool.entries[i]; long hostRef = ref.hostReference; long cleanup = ref.cleanup; // This is a sanity check to prevent calling a cleanup with a null // pointer, it would only occur if we failed to manage a deleted // item. if (cleanup == 0) continue; ref.cleanup = 0; JPypeReferenceNative.removeHostReference(hostRef, cleanup); } pool.tail = 0; } } // static class Pool { JPypeReference[] entries = new JPypeReference[SIZE]; int tail; int id; Pool(int id) { this.id = id; } boolean add(JPypeReference ref) { ref.pool = id; ref.index = tail; entries[tail++] = ref; return (tail == entries.length); } void remove(JPypeReference ref) { entries[ref.index] = entries[--tail]; entries[ref.index].index = ref.index; } } // } jpype-1.3.0/native/jni_include/000077500000000000000000000000001405671516700164275ustar00rootroot00000000000000jpype-1.3.0/native/jni_include/jni.h000066400000000000000000001500431405671516700173630ustar00rootroot00000000000000/* * Copyright (C) 2006 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * JNI specification, as defined by Sun: * http://java.sun.com/javase/6/docs/technotes/guides/jni/spec/jniTOC.html * * Everything here is expected to be VM-neutral. */ #ifndef JNI_H_ #define JNI_H_ #include #ifdef _MSC_VER // broken m$ compiler does not have c99 std header #if _MSC_VER >= 1600 #include #else typedef __int8 int8_t; typedef __int16 int16_t; typedef __int32 int32_t; typedef __int64 int64_t; typedef unsigned __int8 uint8_t; typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; typedef unsigned __int64 uint64_t; #endif #else #include #endif #include /* Primitive types that match up with Java equivalents. */ typedef uint8_t jboolean; /* unsigned 8 bits */ typedef int8_t jbyte; /* signed 8 bits */ typedef uint16_t jchar; /* unsigned 16 bits */ typedef int16_t jshort; /* signed 16 bits */ #if defined(_WIN32) typedef long jint; #else typedef int32_t jint; /* signed 32 bits */ #endif // define jlong #ifdef _LP64 /* 64-bit build */ typedef int64_t jlong; /* signed 64 bits */ // typedef long jlong; #else typedef long long jlong; #endif typedef float jfloat; /* 32-bit IEEE 754 */ typedef double jdouble; /* 64-bit IEEE 754 */ /* "cardinal indices and sizes" */ typedef jint jsize; #ifndef __has_attribute #define __has_attribute(x) 0 #endif #if defined(_WIN32) #define JNIEXPORT __declspec(dllexport) #define JNIIMPORT __declspec(dllimport) #define JNICALL __stdcall #elif (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility) #define JNIEXPORT __attribute__((visibility("default"))) #define JNIIMPORT __attribute__((visibility("default"))) #define JNICALL #else #define JNICALL #define JNIEXPORT #define JNIIMPORT #endif #ifdef __cplusplus /* * Reference types, in C++ */ class _jobject {}; class _jclass : public _jobject {}; class _jstring : public _jobject {}; class _jarray : public _jobject {}; class _jobjectArray : public _jarray {}; class _jbooleanArray : public _jarray {}; class _jbyteArray : public _jarray {}; class _jcharArray : public _jarray {}; class _jshortArray : public _jarray {}; class _jintArray : public _jarray {}; class _jlongArray : public _jarray {}; class _jfloatArray : public _jarray {}; class _jdoubleArray : public _jarray {}; class _jthrowable : public _jobject {}; typedef _jobject* jobject; typedef _jclass* jclass; typedef _jstring* jstring; typedef _jarray* jarray; typedef _jobjectArray* jobjectArray; typedef _jbooleanArray* jbooleanArray; typedef _jbyteArray* jbyteArray; typedef _jcharArray* jcharArray; typedef _jshortArray* jshortArray; typedef _jintArray* jintArray; typedef _jlongArray* jlongArray; typedef _jfloatArray* jfloatArray; typedef _jdoubleArray* jdoubleArray; typedef _jthrowable* jthrowable; typedef _jobject* jweak; #else /* not __cplusplus */ /* * Reference types, in C. */ typedef void* jobject; typedef jobject jclass; typedef jobject jstring; typedef jobject jarray; typedef jarray jobjectArray; typedef jarray jbooleanArray; typedef jarray jbyteArray; typedef jarray jcharArray; typedef jarray jshortArray; typedef jarray jintArray; typedef jarray jlongArray; typedef jarray jfloatArray; typedef jarray jdoubleArray; typedef jobject jthrowable; typedef jobject jweak; #endif /* not __cplusplus */ struct _jfieldID; /* opaque structure */ typedef struct _jfieldID* jfieldID; /* field IDs */ struct _jmethodID; /* opaque structure */ typedef struct _jmethodID* jmethodID; /* method IDs */ struct JNIInvokeInterface; typedef union jvalue { jboolean z; jbyte b; jchar c; jshort s; jint i; jlong j; jfloat f; jdouble d; jobject l; } jvalue; typedef enum jobjectRefType { JNIInvalidRefType = 0, JNILocalRefType = 1, JNIGlobalRefType = 2, JNIWeakGlobalRefType = 3 } jobjectRefType; typedef struct { const char* name; const char* signature; void* fnPtr; } JNINativeMethod; struct _JNIEnv; struct _JavaVM; typedef const struct JNINativeInterface* C_JNIEnv; #if defined(__cplusplus) typedef _JNIEnv JNIEnv; typedef _JavaVM JavaVM; #else typedef const struct JNINativeInterface* JNIEnv; typedef const struct JNIInvokeInterface* JavaVM; #endif /* * Table of interface function pointers. */ struct JNINativeInterface { void* reserved0; void* reserved1; void* reserved2; void* reserved3; jint (*GetVersion)(JNIEnv *); jclass (*DefineClass)(JNIEnv*, const char*, jobject, const jbyte*, jsize); jclass (*FindClass)(JNIEnv*, const char*); jmethodID (*FromReflectedMethod)(JNIEnv*, jobject); jfieldID (*FromReflectedField)(JNIEnv*, jobject); /* spec doesn't show jboolean parameter */ jobject (*ToReflectedMethod)(JNIEnv*, jclass, jmethodID, jboolean); jclass (*GetSuperclass)(JNIEnv*, jclass); jboolean (*IsAssignableFrom)(JNIEnv*, jclass, jclass); /* spec doesn't show jboolean parameter */ jobject (*ToReflectedField)(JNIEnv*, jclass, jfieldID, jboolean); jint (*Throw)(JNIEnv*, jthrowable); jint (*ThrowNew)(JNIEnv *, jclass, const char *); jthrowable (*ExceptionOccurred)(JNIEnv*); void (*ExceptionDescribe)(JNIEnv*); void (*ExceptionClear)(JNIEnv*); void (*FatalError)(JNIEnv*, const char*); jint (*PushLocalFrame)(JNIEnv*, jint); jobject (*PopLocalFrame)(JNIEnv*, jobject); jobject (*NewGlobalRef)(JNIEnv*, jobject); void (*DeleteGlobalRef)(JNIEnv*, jobject); void (*DeleteLocalRef)(JNIEnv*, jobject); jboolean (*IsSameObject)(JNIEnv*, jobject, jobject); jobject (*NewLocalRef)(JNIEnv*, jobject); jint (*EnsureLocalCapacity)(JNIEnv*, jint); jobject (*AllocObject)(JNIEnv*, jclass); jobject (*NewObject)(JNIEnv*, jclass, jmethodID, ...); jobject (*NewObjectV)(JNIEnv*, jclass, jmethodID, va_list); jobject (*NewObjectA)(JNIEnv*, jclass, jmethodID, jvalue*); jclass (*GetObjectClass)(JNIEnv*, jobject); jboolean (*IsInstanceOf)(JNIEnv*, jobject, jclass); jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*); jobject (*CallObjectMethod)(JNIEnv*, jobject, jmethodID, ...); jobject (*CallObjectMethodV)(JNIEnv*, jobject, jmethodID, va_list); jobject (*CallObjectMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jboolean (*CallBooleanMethod)(JNIEnv*, jobject, jmethodID, ...); jboolean (*CallBooleanMethodV)(JNIEnv*, jobject, jmethodID, va_list); jboolean (*CallBooleanMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jbyte (*CallByteMethod)(JNIEnv*, jobject, jmethodID, ...); jbyte (*CallByteMethodV)(JNIEnv*, jobject, jmethodID, va_list); jbyte (*CallByteMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jchar (*CallCharMethod)(JNIEnv*, jobject, jmethodID, ...); jchar (*CallCharMethodV)(JNIEnv*, jobject, jmethodID, va_list); jchar (*CallCharMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jshort (*CallShortMethod)(JNIEnv*, jobject, jmethodID, ...); jshort (*CallShortMethodV)(JNIEnv*, jobject, jmethodID, va_list); jshort (*CallShortMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jint (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...); jint (*CallIntMethodV)(JNIEnv*, jobject, jmethodID, va_list); jint (*CallIntMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jlong (*CallLongMethod)(JNIEnv*, jobject, jmethodID, ...); jlong (*CallLongMethodV)(JNIEnv*, jobject, jmethodID, va_list); jlong (*CallLongMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jfloat (*CallFloatMethod)(JNIEnv*, jobject, jmethodID, ...); jfloat (*CallFloatMethodV)(JNIEnv*, jobject, jmethodID, va_list); jfloat (*CallFloatMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jdouble (*CallDoubleMethod)(JNIEnv*, jobject, jmethodID, ...); jdouble (*CallDoubleMethodV)(JNIEnv*, jobject, jmethodID, va_list); jdouble (*CallDoubleMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...); void (*CallVoidMethodV)(JNIEnv*, jobject, jmethodID, va_list); void (*CallVoidMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jobject (*CallNonvirtualObjectMethod)(JNIEnv*, jobject, jclass, jmethodID, ...); jobject (*CallNonvirtualObjectMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list); jobject (*CallNonvirtualObjectMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*); jboolean (*CallNonvirtualBooleanMethod)(JNIEnv*, jobject, jclass, jmethodID, ...); jboolean (*CallNonvirtualBooleanMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list); jboolean (*CallNonvirtualBooleanMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*); jbyte (*CallNonvirtualByteMethod)(JNIEnv*, jobject, jclass, jmethodID, ...); jbyte (*CallNonvirtualByteMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list); jbyte (*CallNonvirtualByteMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*); jchar (*CallNonvirtualCharMethod)(JNIEnv*, jobject, jclass, jmethodID, ...); jchar (*CallNonvirtualCharMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list); jchar (*CallNonvirtualCharMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*); jshort (*CallNonvirtualShortMethod)(JNIEnv*, jobject, jclass, jmethodID, ...); jshort (*CallNonvirtualShortMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list); jshort (*CallNonvirtualShortMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*); jint (*CallNonvirtualIntMethod)(JNIEnv*, jobject, jclass, jmethodID, ...); jint (*CallNonvirtualIntMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list); jint (*CallNonvirtualIntMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*); jlong (*CallNonvirtualLongMethod)(JNIEnv*, jobject, jclass, jmethodID, ...); jlong (*CallNonvirtualLongMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list); jlong (*CallNonvirtualLongMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*); jfloat (*CallNonvirtualFloatMethod)(JNIEnv*, jobject, jclass, jmethodID, ...); jfloat (*CallNonvirtualFloatMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list); jfloat (*CallNonvirtualFloatMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*); jdouble (*CallNonvirtualDoubleMethod)(JNIEnv*, jobject, jclass, jmethodID, ...); jdouble (*CallNonvirtualDoubleMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list); jdouble (*CallNonvirtualDoubleMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*); void (*CallNonvirtualVoidMethod)(JNIEnv*, jobject, jclass, jmethodID, ...); void (*CallNonvirtualVoidMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list); void (*CallNonvirtualVoidMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*); jfieldID (*GetFieldID)(JNIEnv*, jclass, const char*, const char*); jobject (*GetObjectField)(JNIEnv*, jobject, jfieldID); jboolean (*GetBooleanField)(JNIEnv*, jobject, jfieldID); jbyte (*GetByteField)(JNIEnv*, jobject, jfieldID); jchar (*GetCharField)(JNIEnv*, jobject, jfieldID); jshort (*GetShortField)(JNIEnv*, jobject, jfieldID); jint (*GetIntField)(JNIEnv*, jobject, jfieldID); jlong (*GetLongField)(JNIEnv*, jobject, jfieldID); jfloat (*GetFloatField)(JNIEnv*, jobject, jfieldID); jdouble (*GetDoubleField)(JNIEnv*, jobject, jfieldID); void (*SetObjectField)(JNIEnv*, jobject, jfieldID, jobject); void (*SetBooleanField)(JNIEnv*, jobject, jfieldID, jboolean); void (*SetByteField)(JNIEnv*, jobject, jfieldID, jbyte); void (*SetCharField)(JNIEnv*, jobject, jfieldID, jchar); void (*SetShortField)(JNIEnv*, jobject, jfieldID, jshort); void (*SetIntField)(JNIEnv*, jobject, jfieldID, jint); void (*SetLongField)(JNIEnv*, jobject, jfieldID, jlong); void (*SetFloatField)(JNIEnv*, jobject, jfieldID, jfloat); void (*SetDoubleField)(JNIEnv*, jobject, jfieldID, jdouble); jmethodID (*GetStaticMethodID)(JNIEnv*, jclass, const char*, const char*); jobject (*CallStaticObjectMethod)(JNIEnv*, jclass, jmethodID, ...); jobject (*CallStaticObjectMethodV)(JNIEnv*, jclass, jmethodID, va_list); jobject (*CallStaticObjectMethodA)(JNIEnv*, jclass, jmethodID, jvalue*); jboolean (*CallStaticBooleanMethod)(JNIEnv*, jclass, jmethodID, ...); jboolean (*CallStaticBooleanMethodV)(JNIEnv*, jclass, jmethodID, va_list); jboolean (*CallStaticBooleanMethodA)(JNIEnv*, jclass, jmethodID, jvalue*); jbyte (*CallStaticByteMethod)(JNIEnv*, jclass, jmethodID, ...); jbyte (*CallStaticByteMethodV)(JNIEnv*, jclass, jmethodID, va_list); jbyte (*CallStaticByteMethodA)(JNIEnv*, jclass, jmethodID, jvalue*); jchar (*CallStaticCharMethod)(JNIEnv*, jclass, jmethodID, ...); jchar (*CallStaticCharMethodV)(JNIEnv*, jclass, jmethodID, va_list); jchar (*CallStaticCharMethodA)(JNIEnv*, jclass, jmethodID, jvalue*); jshort (*CallStaticShortMethod)(JNIEnv*, jclass, jmethodID, ...); jshort (*CallStaticShortMethodV)(JNIEnv*, jclass, jmethodID, va_list); jshort (*CallStaticShortMethodA)(JNIEnv*, jclass, jmethodID, jvalue*); jint (*CallStaticIntMethod)(JNIEnv*, jclass, jmethodID, ...); jint (*CallStaticIntMethodV)(JNIEnv*, jclass, jmethodID, va_list); jint (*CallStaticIntMethodA)(JNIEnv*, jclass, jmethodID, jvalue*); jlong (*CallStaticLongMethod)(JNIEnv*, jclass, jmethodID, ...); jlong (*CallStaticLongMethodV)(JNIEnv*, jclass, jmethodID, va_list); jlong (*CallStaticLongMethodA)(JNIEnv*, jclass, jmethodID, jvalue*); jfloat (*CallStaticFloatMethod)(JNIEnv*, jclass, jmethodID, ...); jfloat (*CallStaticFloatMethodV)(JNIEnv*, jclass, jmethodID, va_list); jfloat (*CallStaticFloatMethodA)(JNIEnv*, jclass, jmethodID, jvalue*); jdouble (*CallStaticDoubleMethod)(JNIEnv*, jclass, jmethodID, ...); jdouble (*CallStaticDoubleMethodV)(JNIEnv*, jclass, jmethodID, va_list); jdouble (*CallStaticDoubleMethodA)(JNIEnv*, jclass, jmethodID, jvalue*); void (*CallStaticVoidMethod)(JNIEnv*, jclass, jmethodID, ...); void (*CallStaticVoidMethodV)(JNIEnv*, jclass, jmethodID, va_list); void (*CallStaticVoidMethodA)(JNIEnv*, jclass, jmethodID, jvalue*); jfieldID (*GetStaticFieldID)(JNIEnv*, jclass, const char*, const char*); jobject (*GetStaticObjectField)(JNIEnv*, jclass, jfieldID); jboolean (*GetStaticBooleanField)(JNIEnv*, jclass, jfieldID); jbyte (*GetStaticByteField)(JNIEnv*, jclass, jfieldID); jchar (*GetStaticCharField)(JNIEnv*, jclass, jfieldID); jshort (*GetStaticShortField)(JNIEnv*, jclass, jfieldID); jint (*GetStaticIntField)(JNIEnv*, jclass, jfieldID); jlong (*GetStaticLongField)(JNIEnv*, jclass, jfieldID); jfloat (*GetStaticFloatField)(JNIEnv*, jclass, jfieldID); jdouble (*GetStaticDoubleField)(JNIEnv*, jclass, jfieldID); void (*SetStaticObjectField)(JNIEnv*, jclass, jfieldID, jobject); void (*SetStaticBooleanField)(JNIEnv*, jclass, jfieldID, jboolean); void (*SetStaticByteField)(JNIEnv*, jclass, jfieldID, jbyte); void (*SetStaticCharField)(JNIEnv*, jclass, jfieldID, jchar); void (*SetStaticShortField)(JNIEnv*, jclass, jfieldID, jshort); void (*SetStaticIntField)(JNIEnv*, jclass, jfieldID, jint); void (*SetStaticLongField)(JNIEnv*, jclass, jfieldID, jlong); void (*SetStaticFloatField)(JNIEnv*, jclass, jfieldID, jfloat); void (*SetStaticDoubleField)(JNIEnv*, jclass, jfieldID, jdouble); jstring (*NewString)(JNIEnv*, const jchar*, jsize); jsize (*GetStringLength)(JNIEnv*, jstring); const jchar* (*GetStringChars)(JNIEnv*, jstring, jboolean*); void (*ReleaseStringChars)(JNIEnv*, jstring, const jchar*); jstring (*NewStringUTF)(JNIEnv*, const char*); jsize (*GetStringUTFLength)(JNIEnv*, jstring); /* JNI spec says this returns const jbyte*, but that's inconsistent */ const char* (*GetStringUTFChars)(JNIEnv*, jstring, jboolean*); void (*ReleaseStringUTFChars)(JNIEnv*, jstring, const char*); jsize (*GetArrayLength)(JNIEnv*, jarray); jobjectArray (*NewObjectArray)(JNIEnv*, jsize, jclass, jobject); jobject (*GetObjectArrayElement)(JNIEnv*, jobjectArray, jsize); void (*SetObjectArrayElement)(JNIEnv*, jobjectArray, jsize, jobject); jbooleanArray (*NewBooleanArray)(JNIEnv*, jsize); jbyteArray (*NewByteArray)(JNIEnv*, jsize); jcharArray (*NewCharArray)(JNIEnv*, jsize); jshortArray (*NewShortArray)(JNIEnv*, jsize); jintArray (*NewIntArray)(JNIEnv*, jsize); jlongArray (*NewLongArray)(JNIEnv*, jsize); jfloatArray (*NewFloatArray)(JNIEnv*, jsize); jdoubleArray (*NewDoubleArray)(JNIEnv*, jsize); jboolean* (*GetBooleanArrayElements)(JNIEnv*, jbooleanArray, jboolean*); jbyte* (*GetByteArrayElements)(JNIEnv*, jbyteArray, jboolean*); jchar* (*GetCharArrayElements)(JNIEnv*, jcharArray, jboolean*); jshort* (*GetShortArrayElements)(JNIEnv*, jshortArray, jboolean*); jint* (*GetIntArrayElements)(JNIEnv*, jintArray, jboolean*); jlong* (*GetLongArrayElements)(JNIEnv*, jlongArray, jboolean*); jfloat* (*GetFloatArrayElements)(JNIEnv*, jfloatArray, jboolean*); jdouble* (*GetDoubleArrayElements)(JNIEnv*, jdoubleArray, jboolean*); void (*ReleaseBooleanArrayElements)(JNIEnv*, jbooleanArray, jboolean*, jint); void (*ReleaseByteArrayElements)(JNIEnv*, jbyteArray, jbyte*, jint); void (*ReleaseCharArrayElements)(JNIEnv*, jcharArray, jchar*, jint); void (*ReleaseShortArrayElements)(JNIEnv*, jshortArray, jshort*, jint); void (*ReleaseIntArrayElements)(JNIEnv*, jintArray, jint*, jint); void (*ReleaseLongArrayElements)(JNIEnv*, jlongArray, jlong*, jint); void (*ReleaseFloatArrayElements)(JNIEnv*, jfloatArray, jfloat*, jint); void (*ReleaseDoubleArrayElements)(JNIEnv*, jdoubleArray, jdouble*, jint); void (*GetBooleanArrayRegion)(JNIEnv*, jbooleanArray, jsize, jsize, jboolean*); void (*GetByteArrayRegion)(JNIEnv*, jbyteArray, jsize, jsize, jbyte*); void (*GetCharArrayRegion)(JNIEnv*, jcharArray, jsize, jsize, jchar*); void (*GetShortArrayRegion)(JNIEnv*, jshortArray, jsize, jsize, jshort*); void (*GetIntArrayRegion)(JNIEnv*, jintArray, jsize, jsize, jint*); void (*GetLongArrayRegion)(JNIEnv*, jlongArray, jsize, jsize, jlong*); void (*GetFloatArrayRegion)(JNIEnv*, jfloatArray, jsize, jsize, jfloat*); void (*GetDoubleArrayRegion)(JNIEnv*, jdoubleArray, jsize, jsize, jdouble*); /* spec shows these without const; some jni.h do, some don't */ void (*SetBooleanArrayRegion)(JNIEnv*, jbooleanArray, jsize, jsize, const jboolean*); void (*SetByteArrayRegion)(JNIEnv*, jbyteArray, jsize, jsize, const jbyte*); void (*SetCharArrayRegion)(JNIEnv*, jcharArray, jsize, jsize, const jchar*); void (*SetShortArrayRegion)(JNIEnv*, jshortArray, jsize, jsize, const jshort*); void (*SetIntArrayRegion)(JNIEnv*, jintArray, jsize, jsize, const jint*); void (*SetLongArrayRegion)(JNIEnv*, jlongArray, jsize, jsize, const jlong*); void (*SetFloatArrayRegion)(JNIEnv*, jfloatArray, jsize, jsize, const jfloat*); void (*SetDoubleArrayRegion)(JNIEnv*, jdoubleArray, jsize, jsize, const jdouble*); jint (*RegisterNatives)(JNIEnv*, jclass, const JNINativeMethod*, jint); jint (*UnregisterNatives)(JNIEnv*, jclass); jint (*MonitorEnter)(JNIEnv*, jobject); jint (*MonitorExit)(JNIEnv*, jobject); jint (*GetJavaVM)(JNIEnv*, JavaVM**); void (*GetStringRegion)(JNIEnv*, jstring, jsize, jsize, jchar*); void (*GetStringUTFRegion)(JNIEnv*, jstring, jsize, jsize, char*); void* (*GetPrimitiveArrayCritical)(JNIEnv*, jarray, jboolean*); void (*ReleasePrimitiveArrayCritical)(JNIEnv*, jarray, void*, jint); const jchar* (*GetStringCritical)(JNIEnv*, jstring, jboolean*); void (*ReleaseStringCritical)(JNIEnv*, jstring, const jchar*); jweak (*NewWeakGlobalRef)(JNIEnv*, jobject); void (*DeleteWeakGlobalRef)(JNIEnv*, jweak); jboolean (*ExceptionCheck)(JNIEnv*); jobject (*NewDirectByteBuffer)(JNIEnv*, void*, jlong); void* (*GetDirectBufferAddress)(JNIEnv*, jobject); jlong (*GetDirectBufferCapacity)(JNIEnv*, jobject); /* added in JNI 1.6 */ jobjectRefType (*GetObjectRefType)(JNIEnv*, jobject); }; /* * C++ object wrapper. * * This is usually overlaid on a C struct whose first element is a * JNINativeInterface*. We rely somewhat on compiler behavior. */ struct _JNIEnv { /* do not rename this; it does not seem to be entirely opaque */ const struct JNINativeInterface* functions; #if defined(__cplusplus) jint GetVersion() { return functions->GetVersion(this); } jclass DefineClass(const char *name, jobject loader, const jbyte* buf, jsize bufLen) { return functions->DefineClass(this, name, loader, buf, bufLen); } jclass FindClass(const char* name) { return functions->FindClass(this, name); } jmethodID FromReflectedMethod(jobject method) { return functions->FromReflectedMethod(this, method); } jfieldID FromReflectedField(jobject field) { return functions->FromReflectedField(this, field); } jobject ToReflectedMethod(jclass cls, jmethodID methodID, jboolean isStatic) { return functions->ToReflectedMethod(this, cls, methodID, isStatic); } jclass GetSuperclass(jclass clazz) { return functions->GetSuperclass(this, clazz); } jboolean IsAssignableFrom(jclass clazz1, jclass clazz2) { return functions->IsAssignableFrom(this, clazz1, clazz2); } jobject ToReflectedField(jclass cls, jfieldID fieldID, jboolean isStatic) { return functions->ToReflectedField(this, cls, fieldID, isStatic); } jint Throw(jthrowable obj) { return functions->Throw(this, obj); } jint ThrowNew(jclass clazz, const char* message) { return functions->ThrowNew(this, clazz, message); } jthrowable ExceptionOccurred() { return functions->ExceptionOccurred(this); } void ExceptionDescribe() { functions->ExceptionDescribe(this); } void ExceptionClear() { functions->ExceptionClear(this); } void FatalError(const char* msg) { functions->FatalError(this, msg); } jint PushLocalFrame(jint capacity) { return functions->PushLocalFrame(this, capacity); } jobject PopLocalFrame(jobject result) { return functions->PopLocalFrame(this, result); } jobject NewGlobalRef(jobject obj) { return functions->NewGlobalRef(this, obj); } void DeleteGlobalRef(jobject globalRef) { functions->DeleteGlobalRef(this, globalRef); } void DeleteLocalRef(jobject localRef) { functions->DeleteLocalRef(this, localRef); } jboolean IsSameObject(jobject ref1, jobject ref2) { return functions->IsSameObject(this, ref1, ref2); } jobject NewLocalRef(jobject ref) { return functions->NewLocalRef(this, ref); } jint EnsureLocalCapacity(jint capacity) { return functions->EnsureLocalCapacity(this, capacity); } jobject AllocObject(jclass clazz) { return functions->AllocObject(this, clazz); } jobject NewObject(jclass clazz, jmethodID methodID, ...) { va_list args; va_start(args, methodID); jobject result = functions->NewObjectV(this, clazz, methodID, args); va_end(args); return result; } jobject NewObjectV(jclass clazz, jmethodID methodID, va_list args) { return functions->NewObjectV(this, clazz, methodID, args); } jobject NewObjectA(jclass clazz, jmethodID methodID, jvalue* args) { return functions->NewObjectA(this, clazz, methodID, args); } jclass GetObjectClass(jobject obj) { return functions->GetObjectClass(this, obj); } jboolean IsInstanceOf(jobject obj, jclass clazz) { return functions->IsInstanceOf(this, obj, clazz); } jmethodID GetMethodID(jclass clazz, const char* name, const char* sig) { return functions->GetMethodID(this, clazz, name, sig); } #define CALL_TYPE_METHOD(_jtype, _jname) \ _jtype Call##_jname##Method(jobject obj, jmethodID methodID, ...) \ { \ _jtype result; \ va_list args; \ va_start(args, methodID); \ result = functions->Call##_jname##MethodV(this, obj, methodID, \ args); \ va_end(args); \ return result; \ } #define CALL_TYPE_METHODV(_jtype, _jname) \ _jtype Call##_jname##MethodV(jobject obj, jmethodID methodID, \ va_list args) \ { return functions->Call##_jname##MethodV(this, obj, methodID, args); } #define CALL_TYPE_METHODA(_jtype, _jname) \ _jtype Call##_jname##MethodA(jobject obj, jmethodID methodID, \ jvalue* args) \ { return functions->Call##_jname##MethodA(this, obj, methodID, args); } #define CALL_TYPE(_jtype, _jname) \ CALL_TYPE_METHOD(_jtype, _jname) \ CALL_TYPE_METHODV(_jtype, _jname) \ CALL_TYPE_METHODA(_jtype, _jname) CALL_TYPE(jobject, Object) CALL_TYPE(jboolean, Boolean) CALL_TYPE(jbyte, Byte) CALL_TYPE(jchar, Char) CALL_TYPE(jshort, Short) CALL_TYPE(jint, Int) CALL_TYPE(jlong, Long) CALL_TYPE(jfloat, Float) CALL_TYPE(jdouble, Double) void CallVoidMethod(jobject obj, jmethodID methodID, ...) { va_list args; va_start(args, methodID); functions->CallVoidMethodV(this, obj, methodID, args); va_end(args); } void CallVoidMethodV(jobject obj, jmethodID methodID, va_list args) { functions->CallVoidMethodV(this, obj, methodID, args); } void CallVoidMethodA(jobject obj, jmethodID methodID, jvalue* args) { functions->CallVoidMethodA(this, obj, methodID, args); } #define CALL_NONVIRT_TYPE_METHOD(_jtype, _jname) \ _jtype CallNonvirtual##_jname##Method(jobject obj, jclass clazz, \ jmethodID methodID, ...) \ { \ _jtype result; \ va_list args; \ va_start(args, methodID); \ result = functions->CallNonvirtual##_jname##MethodV(this, obj, \ clazz, methodID, args); \ va_end(args); \ return result; \ } #define CALL_NONVIRT_TYPE_METHODV(_jtype, _jname) \ _jtype CallNonvirtual##_jname##MethodV(jobject obj, jclass clazz, \ jmethodID methodID, va_list args) \ { return functions->CallNonvirtual##_jname##MethodV(this, obj, clazz, \ methodID, args); } #define CALL_NONVIRT_TYPE_METHODA(_jtype, _jname) \ _jtype CallNonvirtual##_jname##MethodA(jobject obj, jclass clazz, \ jmethodID methodID, jvalue* args) \ { return functions->CallNonvirtual##_jname##MethodA(this, obj, clazz, \ methodID, args); } #define CALL_NONVIRT_TYPE(_jtype, _jname) \ CALL_NONVIRT_TYPE_METHOD(_jtype, _jname) \ CALL_NONVIRT_TYPE_METHODV(_jtype, _jname) \ CALL_NONVIRT_TYPE_METHODA(_jtype, _jname) CALL_NONVIRT_TYPE(jobject, Object) CALL_NONVIRT_TYPE(jboolean, Boolean) CALL_NONVIRT_TYPE(jbyte, Byte) CALL_NONVIRT_TYPE(jchar, Char) CALL_NONVIRT_TYPE(jshort, Short) CALL_NONVIRT_TYPE(jint, Int) CALL_NONVIRT_TYPE(jlong, Long) CALL_NONVIRT_TYPE(jfloat, Float) CALL_NONVIRT_TYPE(jdouble, Double) void CallNonvirtualVoidMethod(jobject obj, jclass clazz, jmethodID methodID, ...) { va_list args; va_start(args, methodID); functions->CallNonvirtualVoidMethodV(this, obj, clazz, methodID, args); va_end(args); } void CallNonvirtualVoidMethodV(jobject obj, jclass clazz, jmethodID methodID, va_list args) { functions->CallNonvirtualVoidMethodV(this, obj, clazz, methodID, args); } void CallNonvirtualVoidMethodA(jobject obj, jclass clazz, jmethodID methodID, jvalue* args) { functions->CallNonvirtualVoidMethodA(this, obj, clazz, methodID, args); } jfieldID GetFieldID(jclass clazz, const char* name, const char* sig) { return functions->GetFieldID(this, clazz, name, sig); } jobject GetObjectField(jobject obj, jfieldID fieldID) { return functions->GetObjectField(this, obj, fieldID); } jboolean GetBooleanField(jobject obj, jfieldID fieldID) { return functions->GetBooleanField(this, obj, fieldID); } jbyte GetByteField(jobject obj, jfieldID fieldID) { return functions->GetByteField(this, obj, fieldID); } jchar GetCharField(jobject obj, jfieldID fieldID) { return functions->GetCharField(this, obj, fieldID); } jshort GetShortField(jobject obj, jfieldID fieldID) { return functions->GetShortField(this, obj, fieldID); } jint GetIntField(jobject obj, jfieldID fieldID) { return functions->GetIntField(this, obj, fieldID); } jlong GetLongField(jobject obj, jfieldID fieldID) { return functions->GetLongField(this, obj, fieldID); } jfloat GetFloatField(jobject obj, jfieldID fieldID) { return functions->GetFloatField(this, obj, fieldID); } jdouble GetDoubleField(jobject obj, jfieldID fieldID) { return functions->GetDoubleField(this, obj, fieldID); } void SetObjectField(jobject obj, jfieldID fieldID, jobject value) { functions->SetObjectField(this, obj, fieldID, value); } void SetBooleanField(jobject obj, jfieldID fieldID, jboolean value) { functions->SetBooleanField(this, obj, fieldID, value); } void SetByteField(jobject obj, jfieldID fieldID, jbyte value) { functions->SetByteField(this, obj, fieldID, value); } void SetCharField(jobject obj, jfieldID fieldID, jchar value) { functions->SetCharField(this, obj, fieldID, value); } void SetShortField(jobject obj, jfieldID fieldID, jshort value) { functions->SetShortField(this, obj, fieldID, value); } void SetIntField(jobject obj, jfieldID fieldID, jint value) { functions->SetIntField(this, obj, fieldID, value); } void SetLongField(jobject obj, jfieldID fieldID, jlong value) { functions->SetLongField(this, obj, fieldID, value); } void SetFloatField(jobject obj, jfieldID fieldID, jfloat value) { functions->SetFloatField(this, obj, fieldID, value); } void SetDoubleField(jobject obj, jfieldID fieldID, jdouble value) { functions->SetDoubleField(this, obj, fieldID, value); } jmethodID GetStaticMethodID(jclass clazz, const char* name, const char* sig) { return functions->GetStaticMethodID(this, clazz, name, sig); } #define CALL_STATIC_TYPE_METHOD(_jtype, _jname) \ _jtype CallStatic##_jname##Method(jclass clazz, jmethodID methodID, \ ...) \ { \ _jtype result; \ va_list args; \ va_start(args, methodID); \ result = functions->CallStatic##_jname##MethodV(this, clazz, \ methodID, args); \ va_end(args); \ return result; \ } #define CALL_STATIC_TYPE_METHODV(_jtype, _jname) \ _jtype CallStatic##_jname##MethodV(jclass clazz, jmethodID methodID, \ va_list args) \ { return functions->CallStatic##_jname##MethodV(this, clazz, methodID, \ args); } #define CALL_STATIC_TYPE_METHODA(_jtype, _jname) \ _jtype CallStatic##_jname##MethodA(jclass clazz, jmethodID methodID, \ jvalue* args) \ { return functions->CallStatic##_jname##MethodA(this, clazz, methodID, \ args); } #define CALL_STATIC_TYPE(_jtype, _jname) \ CALL_STATIC_TYPE_METHOD(_jtype, _jname) \ CALL_STATIC_TYPE_METHODV(_jtype, _jname) \ CALL_STATIC_TYPE_METHODA(_jtype, _jname) CALL_STATIC_TYPE(jobject, Object) CALL_STATIC_TYPE(jboolean, Boolean) CALL_STATIC_TYPE(jbyte, Byte) CALL_STATIC_TYPE(jchar, Char) CALL_STATIC_TYPE(jshort, Short) CALL_STATIC_TYPE(jint, Int) CALL_STATIC_TYPE(jlong, Long) CALL_STATIC_TYPE(jfloat, Float) CALL_STATIC_TYPE(jdouble, Double) void CallStaticVoidMethod(jclass clazz, jmethodID methodID, ...) { va_list args; va_start(args, methodID); functions->CallStaticVoidMethodV(this, clazz, methodID, args); va_end(args); } void CallStaticVoidMethodV(jclass clazz, jmethodID methodID, va_list args) { functions->CallStaticVoidMethodV(this, clazz, methodID, args); } void CallStaticVoidMethodA(jclass clazz, jmethodID methodID, jvalue* args) { functions->CallStaticVoidMethodA(this, clazz, methodID, args); } jfieldID GetStaticFieldID(jclass clazz, const char* name, const char* sig) { return functions->GetStaticFieldID(this, clazz, name, sig); } jobject GetStaticObjectField(jclass clazz, jfieldID fieldID) { return functions->GetStaticObjectField(this, clazz, fieldID); } jboolean GetStaticBooleanField(jclass clazz, jfieldID fieldID) { return functions->GetStaticBooleanField(this, clazz, fieldID); } jbyte GetStaticByteField(jclass clazz, jfieldID fieldID) { return functions->GetStaticByteField(this, clazz, fieldID); } jchar GetStaticCharField(jclass clazz, jfieldID fieldID) { return functions->GetStaticCharField(this, clazz, fieldID); } jshort GetStaticShortField(jclass clazz, jfieldID fieldID) { return functions->GetStaticShortField(this, clazz, fieldID); } jint GetStaticIntField(jclass clazz, jfieldID fieldID) { return functions->GetStaticIntField(this, clazz, fieldID); } jlong GetStaticLongField(jclass clazz, jfieldID fieldID) { return functions->GetStaticLongField(this, clazz, fieldID); } jfloat GetStaticFloatField(jclass clazz, jfieldID fieldID) { return functions->GetStaticFloatField(this, clazz, fieldID); } jdouble GetStaticDoubleField(jclass clazz, jfieldID fieldID) { return functions->GetStaticDoubleField(this, clazz, fieldID); } void SetStaticObjectField(jclass clazz, jfieldID fieldID, jobject value) { functions->SetStaticObjectField(this, clazz, fieldID, value); } void SetStaticBooleanField(jclass clazz, jfieldID fieldID, jboolean value) { functions->SetStaticBooleanField(this, clazz, fieldID, value); } void SetStaticByteField(jclass clazz, jfieldID fieldID, jbyte value) { functions->SetStaticByteField(this, clazz, fieldID, value); } void SetStaticCharField(jclass clazz, jfieldID fieldID, jchar value) { functions->SetStaticCharField(this, clazz, fieldID, value); } void SetStaticShortField(jclass clazz, jfieldID fieldID, jshort value) { functions->SetStaticShortField(this, clazz, fieldID, value); } void SetStaticIntField(jclass clazz, jfieldID fieldID, jint value) { functions->SetStaticIntField(this, clazz, fieldID, value); } void SetStaticLongField(jclass clazz, jfieldID fieldID, jlong value) { functions->SetStaticLongField(this, clazz, fieldID, value); } void SetStaticFloatField(jclass clazz, jfieldID fieldID, jfloat value) { functions->SetStaticFloatField(this, clazz, fieldID, value); } void SetStaticDoubleField(jclass clazz, jfieldID fieldID, jdouble value) { functions->SetStaticDoubleField(this, clazz, fieldID, value); } jstring NewString(const jchar* unicodeChars, jsize len) { return functions->NewString(this, unicodeChars, len); } jsize GetStringLength(jstring string) { return functions->GetStringLength(this, string); } const jchar* GetStringChars(jstring string, jboolean* isCopy) { return functions->GetStringChars(this, string, isCopy); } void ReleaseStringChars(jstring string, const jchar* chars) { functions->ReleaseStringChars(this, string, chars); } jstring NewStringUTF(const char* bytes) { return functions->NewStringUTF(this, bytes); } jsize GetStringUTFLength(jstring string) { return functions->GetStringUTFLength(this, string); } const char* GetStringUTFChars(jstring string, jboolean* isCopy) { return functions->GetStringUTFChars(this, string, isCopy); } void ReleaseStringUTFChars(jstring string, const char* utf) { functions->ReleaseStringUTFChars(this, string, utf); } jsize GetArrayLength(jarray array) { return functions->GetArrayLength(this, array); } jobjectArray NewObjectArray(jsize length, jclass elementClass, jobject initialElement) { return functions->NewObjectArray(this, length, elementClass, initialElement); } jobject GetObjectArrayElement(jobjectArray array, jsize index) { return functions->GetObjectArrayElement(this, array, index); } void SetObjectArrayElement(jobjectArray array, jsize index, jobject value) { functions->SetObjectArrayElement(this, array, index, value); } jbooleanArray NewBooleanArray(jsize length) { return functions->NewBooleanArray(this, length); } jbyteArray NewByteArray(jsize length) { return functions->NewByteArray(this, length); } jcharArray NewCharArray(jsize length) { return functions->NewCharArray(this, length); } jshortArray NewShortArray(jsize length) { return functions->NewShortArray(this, length); } jintArray NewIntArray(jsize length) { return functions->NewIntArray(this, length); } jlongArray NewLongArray(jsize length) { return functions->NewLongArray(this, length); } jfloatArray NewFloatArray(jsize length) { return functions->NewFloatArray(this, length); } jdoubleArray NewDoubleArray(jsize length) { return functions->NewDoubleArray(this, length); } jboolean* GetBooleanArrayElements(jbooleanArray array, jboolean* isCopy) { return functions->GetBooleanArrayElements(this, array, isCopy); } jbyte* GetByteArrayElements(jbyteArray array, jboolean* isCopy) { return functions->GetByteArrayElements(this, array, isCopy); } jchar* GetCharArrayElements(jcharArray array, jboolean* isCopy) { return functions->GetCharArrayElements(this, array, isCopy); } jshort* GetShortArrayElements(jshortArray array, jboolean* isCopy) { return functions->GetShortArrayElements(this, array, isCopy); } jint* GetIntArrayElements(jintArray array, jboolean* isCopy) { return functions->GetIntArrayElements(this, array, isCopy); } jlong* GetLongArrayElements(jlongArray array, jboolean* isCopy) { return functions->GetLongArrayElements(this, array, isCopy); } jfloat* GetFloatArrayElements(jfloatArray array, jboolean* isCopy) { return functions->GetFloatArrayElements(this, array, isCopy); } jdouble* GetDoubleArrayElements(jdoubleArray array, jboolean* isCopy) { return functions->GetDoubleArrayElements(this, array, isCopy); } void ReleaseBooleanArrayElements(jbooleanArray array, jboolean* elems, jint mode) { functions->ReleaseBooleanArrayElements(this, array, elems, mode); } void ReleaseByteArrayElements(jbyteArray array, jbyte* elems, jint mode) { functions->ReleaseByteArrayElements(this, array, elems, mode); } void ReleaseCharArrayElements(jcharArray array, jchar* elems, jint mode) { functions->ReleaseCharArrayElements(this, array, elems, mode); } void ReleaseShortArrayElements(jshortArray array, jshort* elems, jint mode) { functions->ReleaseShortArrayElements(this, array, elems, mode); } void ReleaseIntArrayElements(jintArray array, jint* elems, jint mode) { functions->ReleaseIntArrayElements(this, array, elems, mode); } void ReleaseLongArrayElements(jlongArray array, jlong* elems, jint mode) { functions->ReleaseLongArrayElements(this, array, elems, mode); } void ReleaseFloatArrayElements(jfloatArray array, jfloat* elems, jint mode) { functions->ReleaseFloatArrayElements(this, array, elems, mode); } void ReleaseDoubleArrayElements(jdoubleArray array, jdouble* elems, jint mode) { functions->ReleaseDoubleArrayElements(this, array, elems, mode); } void GetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len, jboolean* buf) { functions->GetBooleanArrayRegion(this, array, start, len, buf); } void GetByteArrayRegion(jbyteArray array, jsize start, jsize len, jbyte* buf) { functions->GetByteArrayRegion(this, array, start, len, buf); } void GetCharArrayRegion(jcharArray array, jsize start, jsize len, jchar* buf) { functions->GetCharArrayRegion(this, array, start, len, buf); } void GetShortArrayRegion(jshortArray array, jsize start, jsize len, jshort* buf) { functions->GetShortArrayRegion(this, array, start, len, buf); } void GetIntArrayRegion(jintArray array, jsize start, jsize len, jint* buf) { functions->GetIntArrayRegion(this, array, start, len, buf); } void GetLongArrayRegion(jlongArray array, jsize start, jsize len, jlong* buf) { functions->GetLongArrayRegion(this, array, start, len, buf); } void GetFloatArrayRegion(jfloatArray array, jsize start, jsize len, jfloat* buf) { functions->GetFloatArrayRegion(this, array, start, len, buf); } void GetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len, jdouble* buf) { functions->GetDoubleArrayRegion(this, array, start, len, buf); } void SetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len, const jboolean* buf) { functions->SetBooleanArrayRegion(this, array, start, len, buf); } void SetByteArrayRegion(jbyteArray array, jsize start, jsize len, const jbyte* buf) { functions->SetByteArrayRegion(this, array, start, len, buf); } void SetCharArrayRegion(jcharArray array, jsize start, jsize len, const jchar* buf) { functions->SetCharArrayRegion(this, array, start, len, buf); } void SetShortArrayRegion(jshortArray array, jsize start, jsize len, const jshort* buf) { functions->SetShortArrayRegion(this, array, start, len, buf); } void SetIntArrayRegion(jintArray array, jsize start, jsize len, const jint* buf) { functions->SetIntArrayRegion(this, array, start, len, buf); } void SetLongArrayRegion(jlongArray array, jsize start, jsize len, const jlong* buf) { functions->SetLongArrayRegion(this, array, start, len, buf); } void SetFloatArrayRegion(jfloatArray array, jsize start, jsize len, const jfloat* buf) { functions->SetFloatArrayRegion(this, array, start, len, buf); } void SetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len, const jdouble* buf) { functions->SetDoubleArrayRegion(this, array, start, len, buf); } jint RegisterNatives(jclass clazz, const JNINativeMethod* methods, jint nMethods) { return functions->RegisterNatives(this, clazz, methods, nMethods); } jint UnregisterNatives(jclass clazz) { return functions->UnregisterNatives(this, clazz); } jint MonitorEnter(jobject obj) { return functions->MonitorEnter(this, obj); } jint MonitorExit(jobject obj) { return functions->MonitorExit(this, obj); } jint GetJavaVM(JavaVM** vm) { return functions->GetJavaVM(this, vm); } void GetStringRegion(jstring str, jsize start, jsize len, jchar* buf) { functions->GetStringRegion(this, str, start, len, buf); } void GetStringUTFRegion(jstring str, jsize start, jsize len, char* buf) { return functions->GetStringUTFRegion(this, str, start, len, buf); } void* GetPrimitiveArrayCritical(jarray array, jboolean* isCopy) { return functions->GetPrimitiveArrayCritical(this, array, isCopy); } void ReleasePrimitiveArrayCritical(jarray array, void* carray, jint mode) { functions->ReleasePrimitiveArrayCritical(this, array, carray, mode); } const jchar* GetStringCritical(jstring string, jboolean* isCopy) { return functions->GetStringCritical(this, string, isCopy); } void ReleaseStringCritical(jstring string, const jchar* carray) { functions->ReleaseStringCritical(this, string, carray); } jweak NewWeakGlobalRef(jobject obj) { return functions->NewWeakGlobalRef(this, obj); } void DeleteWeakGlobalRef(jweak obj) { functions->DeleteWeakGlobalRef(this, obj); } jboolean ExceptionCheck() { return functions->ExceptionCheck(this); } jobject NewDirectByteBuffer(void* address, jlong capacity) { return functions->NewDirectByteBuffer(this, address, capacity); } void* GetDirectBufferAddress(jobject buf) { return functions->GetDirectBufferAddress(this, buf); } jlong GetDirectBufferCapacity(jobject buf) { return functions->GetDirectBufferCapacity(this, buf); } /* added in JNI 1.6 */ jobjectRefType GetObjectRefType(jobject obj) { return functions->GetObjectRefType(this, obj); } #endif /*__cplusplus*/ }; /* * JNI invocation interface. */ struct JNIInvokeInterface { void* reserved0; void* reserved1; void* reserved2; jint (*DestroyJavaVM)(JavaVM*); jint (*AttachCurrentThread)(JavaVM*, void**, void*); jint (*DetachCurrentThread)(JavaVM*); jint (*GetEnv)(JavaVM*, void**, jint); jint (*AttachCurrentThreadAsDaemon)(JavaVM*, void**, void*); }; /* * C++ version. */ struct _JavaVM { const struct JNIInvokeInterface* functions; #if defined(__cplusplus) jint DestroyJavaVM() { return functions->DestroyJavaVM(this); } jint AttachCurrentThread(void** p_env, void* thr_args) { return functions->AttachCurrentThread(this, p_env, thr_args); } jint DetachCurrentThread() { return functions->DetachCurrentThread(this); } jint GetEnv(void** env, jint version) { return functions->GetEnv(this, env, version); } jint AttachCurrentThreadAsDaemon(void** p_env, void* thr_args) { return functions->AttachCurrentThreadAsDaemon(this, p_env, thr_args); } #endif /*__cplusplus*/ }; struct JavaVMAttachArgs { jint version; /* must be >= JNI_VERSION_1_2 */ const char* name; /* NULL or name of thread as modified UTF-8 str */ jobject group; /* global ref of a ThreadGroup object, or NULL */ }; typedef struct JavaVMAttachArgs JavaVMAttachArgs; /* * JNI 1.2+ initialization. (As of 1.6, the pre-1.2 structures are no * longer supported.) */ typedef struct JavaVMOption { const char* optionString; void* extraInfo; } JavaVMOption; typedef struct JavaVMInitArgs { jint version; /* use JNI_VERSION_1_2 or later */ jint nOptions; JavaVMOption* options; jboolean ignoreUnrecognized; } JavaVMInitArgs; #ifdef __cplusplus extern "C" { #endif /* * VM initialization functions. * * Note these are the only symbols exported for JNI by the VM. */ jint JNI_GetDefaultJavaVMInitArgs(void*); jint JNI_CreateJavaVM(JavaVM**, JNIEnv**, void*); jint JNI_GetCreatedJavaVMs(JavaVM**, jsize, jsize*); // commented out by marscher //#define JNIIMPORT //#define JNIEXPORT __attribute__ ((visibility ("default"))) //#define JNICALL /* * Prototypes for functions exported by loadable shared libs. These are * called by JNI, not provided by JNI. */ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved); JNIEXPORT void JNI_OnUnload(JavaVM* vm, void* reserved); #ifdef __cplusplus } #endif /* * Manifest constants. */ #define JNI_FALSE 0 #define JNI_TRUE 1 #define JNI_VERSION_1_1 0x00010001 #define JNI_VERSION_1_2 0x00010002 #define JNI_VERSION_1_4 0x00010004 #define JNI_VERSION_1_6 0x00010006 #define JNI_VERSION_1_7 0x00010007 #define JNI_VERSION_1_8 0x00010008 #define JNI_OK (0) /* no error */ #define JNI_ERR (-1) /* generic error */ #define JNI_EDETACHED (-2) /* thread detached from the VM */ #define JNI_EVERSION (-3) /* JNI version error */ #define JNI_COMMIT 1 /* copy content, do not free buffer */ #define JNI_ABORT 2 /* free buffer w/o copying back */ #endif /* JNI_H_ */ jpype-1.3.0/native/python/000077500000000000000000000000001405671516700154655ustar00rootroot00000000000000jpype-1.3.0/native/python/include/000077500000000000000000000000001405671516700171105ustar00rootroot00000000000000jpype-1.3.0/native/python/include/jp_pythontypes.h000077500000000000000000000235101405671516700223640ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef JP_PYTHONTYPES_H_ #define JP_PYTHONTYPES_H_ #include #include /** * This set of source are mostly sugar with some light weight * reference management. Each type holds a reference for the duration of its * scope. If the PyObject must survive the reference container lifespan * then a keep must be called. keep() should only appear when returning from * the python module. Any earlier than the return provides an opportunity for * an exception to be throw which may leak. * * For this module to function properly, each call needs to be check against the * python object model to verify. * 1) Does a call return an object as a new reference or a borrowed one. * 2) Does a call set an error that must be checked. * 3) Does the call steal a reference to an object passed into it. * * Calls should always accept a raw PyObject* and return JPPyObject if * the return can be an new object or PyObject* if the return is a borrowed * reference. Obviously holding a borrowed reference can create issues as * nothing prevents a borrowed object from falling out of the list and * being deleted. * */ // Note: Python uses a sized size type. Thus we will map it to jlong. // Note: for conversions we will use jint and jlong types so that we map directly to java. // Note: Where possible we will use std::string in place of const char* #ifndef PyObject_HEAD struct _object; typedef _object PyObject; #endif /** Reference to a Python object. * * This creates a reference on creation and deletes it on destruction. * * Because there is a cost associated with creating wrappers, most * methods should be static if they don't actually require management. * * Methods will return either a bare PyObject* if they hold the * object like a container, or a wrapper which will control the lifespan * of the object. * * Python has a lot of difference cases for how it returns an object. * - It can give a new object or set an error. * - It can return NULL indicating there is no object. * - It can give a borrowed object or NULL if it doesn't exist. * - Or we can just have an existing object we want to use. * * With all these different methods, we need to have a policy that * state how we want this object reference to be treated. Each * policy will produce different actions on the creation of * a reference wrapper. * */ class JPPyObject { /** Create a new reference to a Python object. * * @param obj is the python object. * @param i is a dummy to make sure this ctor was not called accidentally. */ JPPyObject(PyObject* obj, int i); public: /** * This policy is used if we need to hold a reference to an existing * object for some duration. The object may be null. * * Increment reference count if not null, and decrement when done. */ static JPPyObject use(PyObject* obj); /** * This policy is used when we are given a new reference that we must * destroy. This will steal a reference. * * claim reference, and decremented when done. Clears errors if NULL. */ static JPPyObject accept(PyObject* obj); /** * This policy is used when we are given a new reference that we must * destroy. This will steal a reference. * * Assert not null, claim reference, and decremented when done. * Will throw an exception in the object is null. */ static JPPyObject claim(PyObject* obj); /** * This policy is used when we are capturing an object returned from a python * call that we are responsible for. This will steal a reference. * * Check for errors, assert not null, then claim. * Will throw an exception an error occurs. */ static JPPyObject call(PyObject* obj); JPPyObject() : m_PyObject(NULL) { } JPPyObject(const JPPyObject &self); ~JPPyObject(); JPPyObject& operator=(const JPPyObject& o); /** * Keep an object by creating a reference. * * This should only appear in the return statement in the cpython module. * The reference must not be null. Keep invalidates this handle from any * further use as you were supposed to have called return. * * @return the pointer to the Python object. */ PyObject* keep(); /** Used in special case of exception handling. */ PyObject* keepNull() { PyObject *out = m_PyObject; m_PyObject = NULL; return out; } /** Access the object. This should never appear in * a return statement. */ PyObject* get() { return m_PyObject; } /** Determine if this python reference is null. * * @returns true if null. */ bool isNull() const { return m_PyObject == NULL; } /** * Get a reference to Python None. */ static JPPyObject getNone(); void incref(); void decref(); protected: PyObject* m_PyObject; } ; /**************************************************************************** * String ***************************************************************************/ /** Wrapper for the concept of a Python string. * * For the purposes of this interface we will hide the differences * between unicode and string. */ class JPPyString : public JPPyObject { public: /** Check if the object is a bytes or unicode. * * @returns true if the object is bytes or unicode. */ static bool check(PyObject* obj); /** Create a new string from utf8 encoded string. * Note: java utf8 is not utf8. * * Python2 produced str unless unicode is set to * true. Python3 will always produce a unicode string. * * @param str is the string to convert */ static JPPyObject fromStringUTF8(const string& str); /** Get a UTF-8 encoded string from Python */ static string asStringUTF8(PyObject* obj); static JPPyObject fromCharUTF16(const jchar c); static bool checkCharUTF16(PyObject* obj); static jchar asCharUTF16(PyObject* obj); } ; /**************************************************************************** * Container types ***************************************************************************/ /** Wrapper for a Python sequence. * * In most cases, we will not use this directly, but rather convert to * a JPPyObjectVector for easy access. */ class JPPySequence { JPPyObject m_Sequence; JPPySequence(PyObject* obj) { m_Sequence = JPPyObject::use(obj); } public: /** Needed for named constructor. */ JPPySequence(const JPPySequence& seq) : m_Sequence(seq.m_Sequence) { } /** Use an existing Python sequence in C++. */ static JPPySequence use(PyObject* obj) { return JPPySequence(obj); } JPPyObject operator[](jlong i); jlong size(); private: JPPySequence& operator= (const JPPySequence& ) ; } ; /** For purposes of efficiency, we should only convert a sequence once per * method call. This class is to support that operation. * * THis object is read only. */ class JPPyObjectVector { public: /** Use an existing sequence members as a vector. */ JPPyObjectVector(PyObject* sequence); /** Use an existing sequence members as a vector plus the * object instance. */ JPPyObjectVector(PyObject* inst, PyObject* sequence); size_t size() const { return m_Contents.size(); } PyObject* operator[](ssize_t i) { return m_Contents[i].get(); } JPPyObject& getInstance() { return m_Instance; } private: JPPyObjectVector& operator= (const JPPyObjectVector& ) ; JPPyObjectVector(const JPPyObjectVector& ); private: JPPyObject m_Instance; JPPyObject m_Sequence; vector m_Contents; } ; /**************************************************************************** * Error handling ***************************************************************************/ /** Front end for all Python exception handling. * * To issue an error from within the C++ layer use the appropriate * JP_RAISE_* macro. If within the Python extension module use * the Python interface. * */ namespace JPPyErr { bool fetch(JPPyObject& exceptionClass, JPPyObject& exceptionValue, JPPyObject& exceptionTrace); void restore(JPPyObject& exceptionClass, JPPyObject& exceptionValue, JPPyObject& exceptionTrace); } /** Memory management for handling a python exception currently in progress. */ class JPPyErrFrame { public: JPPyObject m_ExceptionClass; JPPyObject m_ExceptionValue; JPPyObject m_ExceptionTrace; bool good; JPPyErrFrame(); ~JPPyErrFrame(); void clear(); void normalize(); } ; /** Used to establish a python lock when called from a * thread external to python such a java. */ class JPPyCallAcquire { public: /** Acquire the lock. */ JPPyCallAcquire(); /* Release the lock. */ ~JPPyCallAcquire(); private: long m_State; } ; /** Used when leaving python to an external potentially * blocking call */ class JPPyCallRelease { public: /** Release the lock. */ JPPyCallRelease(); /** Reacquire the lock. */ ~JPPyCallRelease(); private: void* m_State1; } ; class JPPyBuffer { public: /** * Attempt to create a buffer view. * * If this fails then valid will return false and * PyExc_BufferError will be set. Clear the exception if * the alternative methods are used. * * @param obj * @param flags */ JPPyBuffer(PyObject* obj, int flags); ~JPPyBuffer(); char *getBufferPtr(std::vector& indices); Py_buffer& getView() { return m_View; } bool valid() { return m_Valid; } private: Py_buffer m_View; bool m_Valid; } ; #endif jpype-1.3.0/native/python/include/pyjp.h000077500000000000000000000155411405671516700202540ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #ifndef PYJP_H #define PYJP_H #include #include "jpype.h" #include "jp_pythontypes.h" class JPStackInfo; #ifdef JP_TRACING_ENABLE #define JP_PY_TRY(...) \ JPypeTracer _trace(__VA_ARGS__); \ try { do {} while(0) #define JP_PY_CATCH(...) \ } catch(...) { \ PyJPModule_rethrow(JP_STACKINFO()); } \ return __VA_ARGS__ #define JP_PY_CATCH_NONE(...) } catch(...) {} return __VA_ARGS__ #else #ifndef JP_INSTRUMENTATION #define JP_PY_TRY(...) try { do {} while(0) #else #define JP_PY_TRY(...) JP_TRACE_IN(__VA_ARGS__) #endif #define JP_PY_CATCH(...) } catch(...) \ { PyJPModule_rethrow(JP_STACKINFO()); } \ return __VA_ARGS__ #define JP_PY_CATCH_NONE(...) } catch(...) {} return __VA_ARGS__ #endif // Macro to all after executing a Python command that can result in // a failure to convert it to an exception. #define JP_PY_CHECK() { if (PyErr_Occurred() != 0) JP_RAISE_PYTHON(); } // GCOVR_EXCL_LINE #ifdef __cplusplus extern "C" { #endif // Needed to write common code with older versions #ifndef Py_TRASHCAN_BEGIN // Introduced in Python 3.8 #define Py_TRASHCAN_BEGIN(X, Y) #define Py_TRASHCAN_END #endif PyMODINIT_FUNC PyInit__jpype(); /** * Set the current exception as the cause of a new exception. * * @param exception * @param str */ void PyJP_SetStringWithCause(PyObject *exception, const char *str); /** * Get a new reference to a method or property in the type dictionary without * dereferencing. * * @param type * @param attr_name * @return */ PyObject* PyJP_GetAttrDescriptor(PyTypeObject *type, PyObject *attr_name); /** * Fast check to see if a type derives from another. * * This depends on the MRO order. It is useful of our base types where * the order is fixed. * * @param type * @param obj * @return 1 if object derives from type. */ int PyJP_IsInstanceSingle(PyObject* obj, PyTypeObject* type); int PyJP_IsSubClassSingle(PyTypeObject* type, PyTypeObject* obj); struct PyJPArray { PyObject_HEAD JPArray *m_Array; JPArrayView *m_View; } ; struct PyJPClassHints { PyObject_HEAD JPClassHints *m_Hints; } ; struct PyJPProxy { PyObject_HEAD JPProxy* m_Proxy; PyObject* m_Target; bool m_Convert; } ; struct JPConversionInfo { PyObject *ret; PyObject *exact; PyObject *implicit; PyObject *attributes; PyObject *expl; PyObject *none; } ; // JPype types extern PyTypeObject *PyJPArray_Type; extern PyTypeObject *PyJPArrayPrimitive_Type; extern PyTypeObject *PyJPBuffer_Type; extern PyTypeObject *PyJPClass_Type; extern PyTypeObject *PyJPComparable_Type; extern PyTypeObject *PyJPMethod_Type; extern PyTypeObject *PyJPObject_Type; extern PyTypeObject *PyJPProxy_Type; extern PyTypeObject *PyJPException_Type; extern PyTypeObject *PyJPNumberLong_Type; extern PyTypeObject *PyJPNumberFloat_Type; extern PyTypeObject *PyJPNumberBool_Type; extern PyTypeObject *PyJPChar_Type; // JPype resources extern PyObject *PyJPModule; extern PyObject *_JArray; extern PyObject *_JChar; extern PyObject *_JObject; extern PyObject *_JInterface; extern PyObject *_JException; extern PyObject *_JClassPre; extern PyObject *_JClassPost; extern PyObject *_JClassDoc; extern PyObject *_JMethodDoc; extern PyObject *_JMethodAnnotations; extern PyObject *_JMethodCode; extern PyObject *_JObjectKey; extern PyObject *_JVMNotRunning; extern PyObject* PyJPClassMagic; extern JPContext* JPContext_global; // Class wrapper functions int PyJPClass_Check(PyObject* obj); PyObject *PyJPClass_FromSpecWithBases(PyType_Spec *spec, PyObject *bases); // Class methods to add to the spec tables PyObject *PyJPValue_alloc(PyTypeObject* type, Py_ssize_t nitems ); void PyJPValue_free(void* obj); void PyJPValue_finalize(void* obj); int PyJPValue_traverse(PyObject *self, visitproc visit, void *arg); int PyJPValue_clear(PyObject *self); // Generic methods that operate on any object with a Java slot PyObject *PyJPValue_str(PyObject* self); bool PyJPValue_hasJavaSlot(PyTypeObject* type); Py_ssize_t PyJPValue_getJavaSlotOffset(PyObject* self); JPValue *PyJPValue_getJavaSlot(PyObject* obj); // Access point for creating classes PyObject *PyJPModule_getClass(PyObject* module, PyObject *obj); PyObject *PyJPValue_getattro(PyObject *obj, PyObject *name); int PyJPValue_setattro(PyObject *self, PyObject *name, PyObject *value); void PyJPClass_hook(JPJavaFrame &frame, JPClass* cls); PyObject *PyJPChar_Create(PyTypeObject *type, Py_UCS2 p); #ifdef __cplusplus } #endif // C++ methods JPPyObject PyJPArray_create(JPJavaFrame &frame, PyTypeObject* wrapper, const JPValue& value); JPPyObject PyJPBuffer_create(JPJavaFrame &frame, PyTypeObject *type, const JPValue & value); JPPyObject PyJPClass_create(JPJavaFrame &frame, JPClass* cls); JPPyObject PyJPNumber_create(JPJavaFrame &frame, JPPyObject& wrapper, const JPValue& value); JPPyObject PyJPField_create(JPField* m); JPPyObject PyJPMethod_create(JPMethodDispatch *m, PyObject *instance); JPClass* PyJPClass_getJPClass(PyObject* obj); JPProxy* PyJPProxy_getJPProxy(PyObject* obj); void PyJPModule_rethrow(const JPStackInfo& info); void PyJPValue_assignJavaSlot(JPJavaFrame &frame, PyObject* obj, const JPValue& value); bool PyJPValue_isSetJavaSlot(PyObject* self); JPPyObject PyTrace_FromJavaException(JPJavaFrame& frame, jthrowable th, jthrowable prev); void PyJPException_normalize(JPJavaFrame frame, JPPyObject exc, jthrowable th, jthrowable enclosing); #define _ASSERT_JVM_RUNNING(context) assertJVMRunning((JPContext*)context, JP_STACKINFO()) /** * Use this when getting the context where the context must be running. * * The context needs to be accessed before accessing and JPClass* or other * internal structured. Those resources are owned by the JVM and thus * will be deleted when the JVM is shutdown. This method will throw if the * JVM is not running. * * If the context may or many not be running access JPContext_global directly. */ inline JPContext* PyJPModule_getContext() { #ifdef JP_INSTRUMENTATION PyJPModuleFault_throw(compile_hash("PyJPModule_getContext")); #endif JPContext* context = JPContext_global; _ASSERT_JVM_RUNNING(context); // GCOVR_EXCL_LINE return context; } void PyJPModule_loadResources(PyObject* module); #endif /* PYJP_H */ jpype-1.3.0/native/python/jp_pythontypes.cpp000066400000000000000000000276621405671516700213050ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "pyjp.h" /**************************************************************************** * Base object ***************************************************************************/ static void assertValid(PyObject *obj) { if (obj->ob_refcnt >= 1) return; // GCOVR_EXCL_START // At this point our car has traveled beyond the end of the // cliff and it will hit the ground some twenty // python calls later with a nearly untracable fault, thus // rather than waiting for the inevitable, we chose to take // a noble death here. JP_TRACE_PY("pyref FAULT", obj); JP_RAISE(PyExc_SystemError, "Deleted reference"); // GCOVR_EXCL_STOP } /** * This policy is used if we need to hold a reference to an existing * object for some duration. The object may be null. * * Increment reference count if not null, and decrement when done. */ JPPyObject JPPyObject::use(PyObject* obj) { JP_TRACE_PY("pyref use(inc)", obj); if (obj != NULL) { assertValid(obj); Py_INCREF(obj); } return JPPyObject(obj, 0); } /** * This policy is used when we are given a new reference that we must * destroy. This will steal a reference. * * claim reference, and decremented when done. */ JPPyObject JPPyObject::accept(PyObject* obj) { JP_TRACE_PY("pyref new(accept)", obj); if (obj == NULL) PyErr_Clear(); return JPPyObject(obj, 1); } /** * This policy is used when we are given a new reference that we must * destroy. This will steal a reference. * * Assert not null, claim reference, and decremented when done. * Will throw an exception if the object is null. */ JPPyObject JPPyObject::claim(PyObject* obj) { JP_TRACE_PY("pyref new(claim)", obj); ASSERT_NOT_NULL(obj); assertValid(obj); return JPPyObject(obj, 2); } /** * This policy is used when we are capturing an object returned from a python * call that we are responsible for. This will steal a reference. * * Check for errors, assert not null, then claim. * Will throw an exception an error occurs. */ JPPyObject JPPyObject::call(PyObject* obj) { JP_TRACE_PY("pyref new(call)", obj); JP_PY_CHECK(); ASSERT_NOT_NULL(obj); assertValid(obj); return JPPyObject(obj, 3); } JPPyObject::JPPyObject(PyObject* obj, int i) : m_PyObject(obj) { } JPPyObject::JPPyObject(const JPPyObject &self) : m_PyObject(self.m_PyObject) { if (m_PyObject != NULL) { incref(); JP_TRACE_PY("pyref copy ctor(inc)", m_PyObject); } } JPPyObject::~JPPyObject() { if (m_PyObject != NULL) { JP_TRACE_PY("pyref dtor(dec)", m_PyObject); decref(); } else { JP_TRACE_PY("pyref dtor(null)", m_PyObject); } } JPPyObject& JPPyObject::operator=(const JPPyObject& self) { if (m_PyObject == self.m_PyObject) return *this; if (m_PyObject != NULL) { JP_TRACE_PY("pyref op=(dec)", m_PyObject); decref(); } m_PyObject = self.m_PyObject; if (m_PyObject != NULL) { incref(); JP_TRACE_PY("pyref op=(inc)", m_PyObject); } return *this; } PyObject* JPPyObject::keep() { // This can only happen if we have a fatal error in our reference // management system. It should never be triggered by the user. if (m_PyObject == NULL) { JP_RAISE(PyExc_SystemError, "Attempt to keep null reference"); // GCOVR_EXCL_LINE } JP_TRACE_PY("pyref keep ", m_PyObject); PyObject *out = m_PyObject; m_PyObject = NULL; return out; } void JPPyObject::incref() { assertValid(m_PyObject); Py_INCREF(m_PyObject); } void JPPyObject::decref() { assertValid(m_PyObject); Py_DECREF(m_PyObject); m_PyObject = 0; } JPPyObject JPPyObject::getNone() { return JPPyObject::use(Py_None); } /**************************************************************************** * String ***************************************************************************/ JPPyObject JPPyString::fromCharUTF16(jchar c) { #if defined(PYPY_VERSION) wchar_t buf[1]; buf[0] = c; return JPPyObject::call(PyUnicode_FromWideChar(buf, 1)); #else if (c < 128) { char c1 = (char) c; return JPPyObject::call(PyUnicode_FromStringAndSize(&c1, 1)); } JPPyObject buf = JPPyObject::call(PyUnicode_New(1, 65535)); Py_UCS4 c2 = c; PyUnicode_WriteChar(buf.get(), 0, c2); JP_PY_CHECK(); PyUnicode_READY(buf.get()); return buf; #endif } bool JPPyString::checkCharUTF16(PyObject* pyobj) { JP_TRACE_IN("JPPyString::checkCharUTF16"); if (PyIndex_Check(pyobj)) return true; if (PyUnicode_Check(pyobj) && PyUnicode_GetLength(pyobj) == 1) return true; if (PyBytes_Check(pyobj) && PyBytes_Size(pyobj) == 1) return true; return false; JP_TRACE_OUT; // GCOVR_EXCL_LINE } jchar JPPyString::asCharUTF16(PyObject* pyobj) { if (PyIndex_Check(pyobj)) { jlong val = PyLong_AsLongLong(pyobj); if (val < 0 || val > 65535) JP_RAISE(PyExc_OverflowError, "Unable to convert int into char range"); return (jchar) val; } #if defined(PYPY_VERSION) if (PyBytes_Check(pyobj)) { int sz = PyBytes_Size(pyobj); if (sz != 1) JP_RAISE(PyExc_ValueError, "Char must be length 1"); jchar c = PyBytes_AsString(pyobj)[0]; if (PyErr_Occurred()) JP_RAISE_PYTHON(); return c; } if (PyUnicode_Check(pyobj)) { if (PyUnicode_GetLength(pyobj) > 1) JP_RAISE(PyExc_ValueError, "Char must be length 1"); PyUnicode_READY(pyobj); Py_UCS4 value = PyUnicode_READ_CHAR(pyobj, 0); if (value > 0xffff) { JP_RAISE(PyExc_ValueError, "Unable to pack 4 byte unicode into java char"); } return value; } #else if (PyBytes_Check(pyobj)) { Py_ssize_t sz = PyBytes_Size(pyobj); if (sz != 1) JP_RAISE(PyExc_ValueError, "Char must be length 1"); jchar c = PyBytes_AsString(pyobj)[0]; JP_PY_CHECK(); return c; } if (PyUnicode_Check(pyobj)) { if (PyUnicode_GetLength(pyobj) > 1) JP_RAISE(PyExc_ValueError, "Char must be length 1"); PyUnicode_READY(pyobj); Py_UCS4 value = PyUnicode_ReadChar(pyobj, 0); if (value > 0xffff) { JP_RAISE(PyExc_ValueError, "Unable to pack 4 byte unicode into java char"); } return value; } #endif PyErr_Format(PyExc_TypeError, "Unable to convert '%s' to char", Py_TYPE(pyobj)->tp_name); JP_RAISE_PYTHON(); } /** Check if the object is a bytes or unicode. * * @returns true if the object is bytes or unicode. */ bool JPPyString::check(PyObject* obj) { return PyUnicode_Check(obj) || PyBytes_Check(obj); } /** Create a new string from utf8 encoded string. * Note: java utf8 is not utf8. */ JPPyObject JPPyString::fromStringUTF8(const string& str) { size_t len = str.size(); // Python 3 is always unicode JPPyObject bytes = JPPyObject::call(PyBytes_FromStringAndSize(str.c_str(), len)); return JPPyObject::call(PyUnicode_FromEncodedObject(bytes.get(), "UTF-8", "strict")); } string JPPyString::asStringUTF8(PyObject* pyobj) { JP_TRACE_IN("JPPyUnicode::asStringUTF8"); ASSERT_NOT_NULL(pyobj); if (PyUnicode_Check(pyobj)) { Py_ssize_t size = 0; char *buffer = NULL; JPPyObject val = JPPyObject::call(PyUnicode_AsEncodedString(pyobj, "UTF-8", "strict")); PyBytes_AsStringAndSize(val.get(), &buffer, &size); JP_PY_CHECK(); if (buffer != NULL) return string(buffer, size); else return string(); } else if (PyBytes_Check(pyobj)) { Py_ssize_t size = 0; char *buffer = NULL; PyBytes_AsStringAndSize(pyobj, &buffer, &size); JP_PY_CHECK(); return string(buffer, size); } // GCOVR_EXCL_START JP_RAISE(PyExc_TypeError, "Failed to convert to string."); return string(); JP_TRACE_OUT; // GCOVR_EXCL_STOP } /**************************************************************************** * Container types ***************************************************************************/ jlong JPPySequence::size() { return PySequence_Size(m_Sequence.get()); } JPPyObject JPPySequence::operator[](jlong i) { return JPPyObject::call(PySequence_GetItem(m_Sequence.get(), i)); // new reference } JPPyObjectVector::JPPyObjectVector(PyObject* sequence) { m_Sequence = JPPyObject::use(sequence); size_t n = PySequence_Size(m_Sequence.get()); m_Contents.resize(n); for (size_t i = 0; i < n; ++i) { m_Contents[i] = JPPyObject::call(PySequence_GetItem(m_Sequence.get(), i)); } } JPPyObjectVector::JPPyObjectVector(PyObject* inst, PyObject* sequence) { m_Instance = JPPyObject::use(inst); m_Sequence = JPPyObject::use(sequence); size_t n = 0; if (sequence != NULL) n = PySequence_Size(m_Sequence.get()); m_Contents.resize(n + 1); for (size_t i = 0; i < n; ++i) { m_Contents[i + 1] = JPPyObject::call(PySequence_GetItem(m_Sequence.get(), i)); } m_Contents[0] = m_Instance; } bool JPPyErr::fetch(JPPyObject& exceptionClass, JPPyObject& exceptionValue, JPPyObject& exceptionTrace) { PyObject *v1, *v2, *v3; PyErr_Fetch(&v1, &v2, &v3); if (v1 == NULL && v2 == NULL && v3 == NULL) return false; exceptionClass = JPPyObject::accept(v1); exceptionValue = JPPyObject::accept(v2); exceptionTrace = JPPyObject::accept(v3); return true; } void JPPyErr::restore(JPPyObject& exceptionClass, JPPyObject& exceptionValue, JPPyObject& exceptionTrace) { PyErr_Restore(exceptionClass.keepNull(), exceptionValue.keepNull(), exceptionTrace.keepNull()); } int m_count = 0; JPPyCallAcquire::JPPyCallAcquire() { m_State = (long) PyGILState_Ensure(); } JPPyCallAcquire::~JPPyCallAcquire() { PyGILState_Release((PyGILState_STATE) m_State); } // This is used when leaving python from to perform some JPPyCallRelease::JPPyCallRelease() { // Release the lock and set the thread state to NULL m_State1 = (void*) PyEval_SaveThread(); } JPPyCallRelease::~JPPyCallRelease() { // Reaquire the lock PyThreadState *save = (PyThreadState *) m_State1; PyEval_RestoreThread(save); } JPPyBuffer::JPPyBuffer(PyObject* obj, int flags) { int ret = PyObject_GetBuffer(obj, &m_View, flags); m_Valid = (ret != -1); } JPPyBuffer::~JPPyBuffer() { if (m_Valid) PyBuffer_Release(&m_View); } char *JPPyBuffer::getBufferPtr(std::vector& indices) { char *pointer = (char*) m_View.buf; // No shape is just a 1D array if (m_View.shape == NULL) { return pointer; } // No strides is C contiguous ND array if (m_View.strides == NULL) { Py_ssize_t index = 0; for (int i = 0; i < m_View.ndim; i++) { index = index * m_View.shape[i] + indices[i]; } index *= m_View.itemsize; return pointer + index; } // Otherwise we can be a full array for (int i = 0; i < m_View.ndim; i++) { pointer += m_View.strides[i] * indices[i]; if (m_View.suboffsets != NULL && m_View.suboffsets[i] >= 0 ) { pointer = *((char**) pointer) + m_View.suboffsets[i]; } } return pointer; } JPPyErrFrame::JPPyErrFrame() { good = JPPyErr::fetch(m_ExceptionClass, m_ExceptionValue, m_ExceptionTrace); } JPPyErrFrame::~JPPyErrFrame() { try { if (good) JPPyErr::restore(m_ExceptionClass, m_ExceptionValue, m_ExceptionTrace); } catch (...) // GCOVR_EXCL_LINE { // No throw is allowed in dtor. } } void JPPyErrFrame::clear() { good = false; } void JPPyErrFrame::normalize() { // Python uses lazy evaluation on exceptions thus we can't modify it until // we have forced it to realize the exception. if (!PyExceptionInstance_Check(m_ExceptionValue.get())) { JPPyObject args = JPPyObject::call(PyTuple_Pack(1, m_ExceptionValue.get())); m_ExceptionValue = JPPyObject::call(PyObject_Call(m_ExceptionClass.get(), args.get(), NULL)); PyException_SetTraceback(m_ExceptionValue.get(), m_ExceptionTrace.get()); JPPyErr::restore(m_ExceptionClass, m_ExceptionValue, m_ExceptionTrace); JPPyErr::fetch(m_ExceptionClass, m_ExceptionValue, m_ExceptionTrace); } } jpype-1.3.0/native/python/pyjp_array.cpp000066400000000000000000000337131405671516700203600ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "pyjp.h" #include "jp_array.h" #include "jp_arrayclass.h" #ifdef __cplusplus extern "C" { #endif /** * Create a new object. * * This is only called from the Python side. * * @param type * @param args * @param kwargs * @return */ static PyObject *PyJPArray_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { JP_PY_TRY("PyJPArray_new"); PyJPArray* self = (PyJPArray*) type->tp_alloc(type, 0); JP_PY_CHECK(); self->m_Array = NULL; self->m_View = NULL; return (PyObject*) self; JP_PY_CATCH(NULL); } static int PyJPArray_init(PyObject *self, PyObject *args, PyObject *kwargs) { JP_PY_TRY("PyJPArray_init"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); // Cases here. // - We got here with a JPValue // - We get an integer. Just create a new array with desired size. // - We get a sequence. Allocate with desired size and call setItems. // - We get something else.... ??? PyObject* v; if (!PyArg_ParseTuple(args, "O", &v)) return -1; JPClass *cls = PyJPClass_getJPClass((PyObject*) Py_TYPE(self)); JPArrayClass* arrayClass = dynamic_cast (cls); if (arrayClass == NULL) JP_RAISE(PyExc_TypeError, "Class must be array type"); JPValue *value = PyJPValue_getJavaSlot(v); if (value != NULL) { JPArrayClass* arrayClass2 = dynamic_cast (value->getClass()); if (arrayClass2 == NULL) JP_RAISE(PyExc_TypeError, "Class must be array type"); if (arrayClass2 != arrayClass) JP_RAISE(PyExc_TypeError, "Array class mismatch"); ((PyJPArray*) self)->m_Array = new JPArray(*value); PyJPValue_assignJavaSlot(frame, self, *value); return 0; } if (PySequence_Check(v)) { JP_TRACE("Sequence"); jlong length = PySequence_Size(v); if (length < 0 || length > 2147483647) JP_RAISE(PyExc_ValueError, "Array size invalid"); JPValue newArray = arrayClass->newArray(frame, (int) length); ((PyJPArray*) self)->m_Array = new JPArray(newArray); ((PyJPArray*) self)->m_Array->setRange(0, (jsize) length, 1, v); PyJPValue_assignJavaSlot(frame, self, newArray); return 0; } if (PyIndex_Check(v)) { JP_TRACE("Index"); long long length = PyLong_AsLongLong(v); if (length < 0 || length > 2147483647) JP_RAISE(PyExc_ValueError, "Array size invalid"); JPValue newArray = arrayClass->newArray(frame, (int) length); ((PyJPArray*) self)->m_Array = new JPArray(newArray); PyJPValue_assignJavaSlot(frame, self, newArray); return 0; } JP_FAULT_RETURN("PyJPArray_init.null", 0); JP_RAISE(PyExc_TypeError, "Invalid type"); JP_PY_CATCH(-1); } static void PyJPArray_dealloc(PyJPArray *self) { JP_PY_TRY("PyJPArray_dealloc"); delete self->m_Array; Py_TYPE(self)->tp_free(self); JP_PY_CATCH(); // GCOVR_EXCL_LINE } static PyObject *PyJPArray_repr(PyJPArray *self) { JP_PY_TRY("PyJPArray_repr"); return PyUnicode_FromFormat("", Py_TYPE(self)->tp_name); JP_PY_CATCH(0); } static Py_ssize_t PyJPArray_len(PyJPArray *self) { JP_PY_TRY("PyJPArray_len"); PyJPModule_getContext(); if (self->m_Array == NULL) JP_RAISE(PyExc_ValueError, "Null array"); // GCOVR_EXCL_LINE return self->m_Array->getLength(); JP_PY_CATCH(-1); } static PyObject* PyJPArray_length(PyJPArray *self, PyObject *closure) { return PyLong_FromSsize_t(PyJPArray_len(self)); } static PyObject *PyJPArray_getItem(PyJPArray *self, PyObject *item) { JP_PY_TRY("PyJPArray_getArrayItem"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); if (self->m_Array == NULL) JP_RAISE(PyExc_ValueError, "Null array"); if (PyIndex_Check(item)) { Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); if (i == -1 && PyErr_Occurred()) return NULL; // GCOVR_EXCL_LINE return self->m_Array->getItem((jsize) i).keep(); } if (PySlice_Check(item)) { Py_ssize_t start, stop, step, slicelength; Py_ssize_t length = (Py_ssize_t) self->m_Array->getLength(); #if PY_VERSION_HEX<0x03060100 if (PySlice_GetIndicesEx(item, length, &start, &stop, &step, &slicelength) < 0) return NULL; #else if (PySlice_Unpack(item, &start, &stop, &step) < 0) return NULL; slicelength = PySlice_AdjustIndices(length, &start, &stop, step); #endif if (slicelength <= 0) { // This should point to a null array so we don't hold worthless // memory, but this is a low priority start = stop = 0; step = 1; } JPPyObject tuple = JPPyObject::call(PyTuple_New(0)); JPPyObject newArray = JPPyObject::claim(Py_TYPE(self)->tp_new(Py_TYPE(self), tuple.get(), NULL)); // Copy over the JPValue PyJPValue_assignJavaSlot(frame, newArray.get(), *PyJPValue_getJavaSlot((PyObject*) self)); // Set up JPArray as slice JPArray *array = ((PyJPArray*) self)->m_Array; ((PyJPArray*) newArray.get())->m_Array = new JPArray(array, (jsize) start, (jsize) stop, (jsize) step); return newArray.keep(); } JP_RAISE(PyExc_TypeError, "Unsupported getItem type"); JP_PY_CATCH(NULL); } static int PyJPArray_assignSubscript(PyJPArray *self, PyObject *item, PyObject *value) { JP_PY_TRY("PyJPArray_assignSubscript"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); // Verified with numpy that item deletion on immutable should // be ValueError if ( value == NULL) JP_RAISE(PyExc_ValueError, "item deletion not supported"); if (self->m_Array == NULL) JP_RAISE(PyExc_ValueError, "Null array"); // Watch out for self assignment if (PyObject_IsInstance(value, (PyObject*) PyJPArray_Type)) { JPValue *v1 = PyJPValue_getJavaSlot((PyObject*) self); JPValue *v2 = PyJPValue_getJavaSlot((PyObject*) value); if (frame.equals(v1->getJavaObject(), v2->getJavaObject())) JP_RAISE(PyExc_ValueError, "self assignment not support currently"); } if (PyIndex_Check(item)) { Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); if (i == -1 && PyErr_Occurred()) return -1; // GCOVR_EXCL_LINE self->m_Array->setItem((jsize) i, value); return 0; } if (PySlice_Check(item)) { Py_ssize_t start, stop, step, slicelength; Py_ssize_t length = (Py_ssize_t) self->m_Array->getLength(); #if PY_VERSION_HEX<0x03060100 if (PySlice_GetIndicesEx(item, length, &start, &stop, &step, &slicelength) < 0) return -1; #else if (PySlice_Unpack(item, &start, &stop, &step) < 0) return -1; slicelength = PySlice_AdjustIndices(length, &start, &stop, step); #endif if (slicelength <= 0) return 0; self->m_Array->setRange((jsize) start, (jsize) slicelength, (jsize) step, value); return 0; } PyErr_Format(PyExc_TypeError, "Java array indices must be integers or slices, not '%s'", Py_TYPE(item)->tp_name); JP_PY_CATCH(-1); } static void PyJPArray_releaseBuffer(PyJPArray *self, Py_buffer *view) { JP_PY_TRY("PyJPArrayPrimitive_releaseBuffer"); JPContext* context = JPContext_global; if (!context->isRunning()) { delete self->m_View; self->m_View = NULL; return; } JPJavaFrame frame = JPJavaFrame::outer(context); if (self->m_View == NULL || !self->m_View->unreference()) return; delete self->m_View; self->m_View = NULL; JP_PY_CATCH(); // GCOVR_EXCL_LINE } int PyJPArray_getBuffer(PyJPArray *self, Py_buffer *view, int flags) { JP_PY_TRY("PyJPArray_getBuffer"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); if (self->m_Array == NULL) JP_RAISE(PyExc_ValueError, "Null array"); if (!self->m_Array->getClass()->isPrimitiveArray()) { PyErr_SetString(PyExc_BufferError, "Java array is not primitive array"); return -1; } if ((flags & PyBUF_WRITEABLE) == PyBUF_WRITEABLE) { PyErr_SetString(PyExc_BufferError, "Java array buffer is not writable"); return -1; } //Check to see if we are a slice and clone it if necessary jarray obj = self->m_Array->getJava(); if (self->m_Array->isSlice()) obj = self->m_Array->clone(frame, (PyObject*) self); jobject result; try { // Collect the members into a rectangular array if possible. result = frame.collectRectangular(obj); } catch (JPypeException &ex) { // No matter what happens we are only allowed to throw BufferError PyErr_SetString(PyExc_BufferError, "Problem in Java buffer extraction"); return -1; } if (result == NULL) { PyErr_SetString(PyExc_BufferError, "Java array buffer is not rectangular primitives"); return -1; } // If it is rectangular so try to create a view try { if (self->m_View == NULL) self->m_View = new JPArrayView(self->m_Array, result); JP_PY_CHECK(); self->m_View->reference(); *view = self->m_View->m_Buffer; // If strides are not requested and this is a slice then fail if ((flags & PyBUF_STRIDES) != PyBUF_STRIDES) view->strides = NULL; // If shape is not requested if ((flags & PyBUF_ND) != PyBUF_ND) view->shape = NULL; // If format is not requested if ((flags & PyBUF_FORMAT) != PyBUF_FORMAT) view->format = NULL; // Okay all successful so reference the parent object view->obj = (PyObject*) self; Py_INCREF(view->obj); return 0; } catch (JPypeException &ex) // GCOVR_EXCL_LINE { // GCOVR_EXCL_START // Release the partial buffer so we don't leak PyJPArray_releaseBuffer(self, view); // We are only allowed to raise BufferError PyErr_SetString(PyExc_BufferError, "Java array view failed"); return -1; // GCOVR_EXCL_STOP } JP_PY_CATCH(-1); // GCOVR_EXCL_LINE } int PyJPArrayPrimitive_getBuffer(PyJPArray *self, Py_buffer *view, int flags) { JP_PY_TRY("PyJPArrayPrimitive_getBuffer"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); if (self->m_Array == NULL) JP_RAISE(PyExc_ValueError, "Null array"); try { if ((flags & PyBUF_WRITEABLE) == PyBUF_WRITEABLE) { PyErr_SetString(PyExc_BufferError, "Java array buffer is not writable"); return -1; } if (self->m_View == NULL) { self->m_View = new JPArrayView(self->m_Array); } self->m_View->reference(); *view = self->m_View->m_Buffer; // We are always contiguous so no need to check that here. view->readonly = 1; // If strides are not requested and this is a slice then fail if ((flags & PyBUF_STRIDES) != PyBUF_STRIDES) { if (view->strides[0] != view->itemsize) JP_RAISE(PyExc_BufferError, "slices required strides"); view->strides = NULL; } // If shape is not requested if ((flags & PyBUF_ND) != PyBUF_ND) { view->shape = NULL; } // If format is not requested if ((flags & PyBUF_FORMAT) != PyBUF_FORMAT) view->format = NULL; // Okay all successful so reference the parent object view->obj = (PyObject*) self; Py_INCREF(view->obj); return 0; } catch (JPypeException &ex) { PyJPArray_releaseBuffer(self, view); // We are only allowed to raise BufferError PyErr_SetString(PyExc_BufferError, "Java array view failed"); return -1; } JP_PY_CATCH(-1); } static const char *length_doc = "Get the length of a Java array\n" "\n" "This method is provided for compatibility with Java syntax.\n" "Generally, the Python style ``len(array)`` should be preferred.\n"; static PyMethodDef arrayMethods[] = { {"__getitem__", (PyCFunction) (&PyJPArray_getItem), METH_O | METH_COEXIST, ""}, {NULL}, }; static PyGetSetDef arrayGetSets[] = { {"length", (getter) (&PyJPArray_length), NULL, const_cast (length_doc)}, {0} }; static PyType_Slot arraySlots[] = { { Py_tp_new, (void*) PyJPArray_new}, { Py_tp_init, (void*) PyJPArray_init}, { Py_tp_dealloc, (void*) PyJPArray_dealloc}, { Py_tp_repr, (void*) PyJPArray_repr}, { Py_tp_methods, (void*) &arrayMethods}, { Py_mp_subscript, (void*) &PyJPArray_getItem}, { Py_sq_length, (void*) &PyJPArray_len}, { Py_tp_getset, (void*) &arrayGetSets}, { Py_mp_ass_subscript, (void*) &PyJPArray_assignSubscript}, {0} }; static PyBufferProcs arrayBuffer = { (getbufferproc) & PyJPArray_getBuffer, (releasebufferproc) & PyJPArray_releaseBuffer }; PyTypeObject *PyJPArray_Type = NULL; static PyType_Spec arraySpec = { "_jpype._JArray", sizeof (PyJPArray), 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, arraySlots }; static PyBufferProcs arrayPrimBuffer = { (getbufferproc) & PyJPArrayPrimitive_getBuffer, (releasebufferproc) & PyJPArray_releaseBuffer }; static PyType_Slot arrayPrimSlots[] = { {0} }; PyTypeObject *PyJPArrayPrimitive_Type = NULL; static PyType_Spec arrayPrimSpec = { "_jpype._JArrayPrimitive", 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, arrayPrimSlots }; #ifdef __cplusplus } #endif void PyJPArray_initType(PyObject * module) { JPPyObject tuple = JPPyObject::call(PyTuple_Pack(1, PyJPObject_Type)); PyJPArray_Type = (PyTypeObject*) PyJPClass_FromSpecWithBases(&arraySpec, tuple.get()); JP_PY_CHECK(); PyJPArray_Type->tp_as_buffer = &arrayBuffer; PyModule_AddObject(module, "_JArray", (PyObject*) PyJPArray_Type); JP_PY_CHECK(); tuple = JPPyObject::call(PyTuple_Pack(1, PyJPArray_Type)); PyJPArrayPrimitive_Type = (PyTypeObject*) PyJPClass_FromSpecWithBases(&arrayPrimSpec, tuple.get()); PyJPArrayPrimitive_Type->tp_as_buffer = &arrayPrimBuffer; JP_PY_CHECK(); PyModule_AddObject(module, "_JArrayPrimitive", (PyObject*) PyJPArrayPrimitive_Type); JP_PY_CHECK(); } JPPyObject PyJPArray_create(JPJavaFrame &frame, PyTypeObject *type, const JPValue & value) { PyObject *obj = type->tp_alloc(type, 0); JP_PY_CHECK(); ((PyJPArray*) obj)->m_Array = new JPArray(value); PyJPValue_assignJavaSlot(frame, obj, value); return JPPyObject::claim(obj); } jpype-1.3.0/native/python/pyjp_buffer.cpp000066400000000000000000000100471405671516700205060ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "pyjp.h" #include "jp_buffer.h" #include "jp_buffertype.h" #ifdef __cplusplus extern "C" { #endif struct PyJPBuffer { PyObject_HEAD JPBuffer *m_Buffer; } ; static void PyJPBuffer_dealloc(PyJPBuffer *self) { JP_PY_TRY("PyJPBuffer_dealloc"); delete self->m_Buffer; Py_TYPE(self)->tp_free(self); JP_PY_CATCH(); // GCOV_EXCL_LINE } static PyObject *PyJPBuffer_repr(PyJPBuffer *self) { JP_PY_TRY("PyJPBuffer_repr"); return PyUnicode_FromFormat("", Py_TYPE(self)->tp_name); JP_PY_CATCH(0); // GCOVR_EXCL_LINE } static void PyJPBuffer_releaseBuffer(PyJPBuffer *self, Py_buffer *view) { JP_PY_TRY("PyJPBufferPrimitive_releaseBuffer"); JP_PY_CATCH(); // GCOVR_EXCL_LINE } int PyJPBuffer_getBuffer(PyJPBuffer *self, Py_buffer *view, int flags) { JP_PY_TRY("PyJPBufferPrimitive_getBuffer"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); if (self->m_Buffer == NULL) JP_RAISE(PyExc_ValueError, "Null buffer"); // GCOVR_EXCL_LINE try { JPBuffer *buffer = self->m_Buffer; if (!buffer->isValid()) { PyErr_SetString(PyExc_BufferError, "Java buffer is not direct"); return -1; } if (buffer->isReadOnly() && (flags & PyBUF_WRITEABLE) == PyBUF_WRITEABLE) { PyErr_SetString(PyExc_BufferError, "Java buffer is not writable"); return -1; } *view = buffer->getView(); // If strides are not requested and this is a slice then fail if ((flags & PyBUF_STRIDES) != PyBUF_STRIDES) { if (view->strides[0] != view->itemsize) JP_RAISE(PyExc_BufferError, "slices required strides"); view->strides = NULL; } // If shape is not requested if ((flags & PyBUF_ND) != PyBUF_ND) { view->shape = NULL; } // If format is not requested if ((flags & PyBUF_FORMAT) != PyBUF_FORMAT) view->format = NULL; // Okay all successful so reference the parent object view->obj = (PyObject*) self; Py_INCREF(view->obj); return 0; } catch (JPypeException &ex) // GCOVR_EXCL_LINE { // GCOVR_EXCL_START PyJPBuffer_releaseBuffer(self, view); // We are only allowed to raise BufferError PyErr_SetString(PyExc_BufferError, "Java buffer view failed"); return -1; // GCOVR_EXCL_STOP } JP_PY_CATCH(-1); // GCOVR_EXCL_LINE } static PyType_Slot bufferSlots[] = { { Py_tp_dealloc, (void*) PyJPBuffer_dealloc}, { Py_tp_repr, (void*) PyJPBuffer_repr}, {0} }; static PyBufferProcs directBuffer = { (getbufferproc) & PyJPBuffer_getBuffer, (releasebufferproc) & PyJPBuffer_releaseBuffer }; PyTypeObject *PyJPBuffer_Type = NULL; static PyType_Spec bufferSpec = { "_jpype._JBuffer", sizeof (PyJPBuffer), 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, bufferSlots }; #ifdef __cplusplus } #endif void PyJPBuffer_initType(PyObject * module) { JPPyObject tuple = JPPyObject::call(PyTuple_Pack(1, PyJPObject_Type)); PyJPBuffer_Type = (PyTypeObject*) PyJPClass_FromSpecWithBases(&bufferSpec, tuple.get()); PyJPBuffer_Type->tp_as_buffer = &directBuffer; JP_PY_CHECK(); PyModule_AddObject(module, "_JBuffer", (PyObject*) PyJPBuffer_Type); JP_PY_CHECK(); } JPPyObject PyJPBuffer_create(JPJavaFrame &frame, PyTypeObject *type, const JPValue& value) { JPPyObject obj = JPPyObject::call(type->tp_alloc(type, 0)); ((PyJPBuffer*) obj.get())->m_Buffer = new JPBuffer(value); PyJPValue_assignJavaSlot(frame, obj.get(), value); return obj; } jpype-1.3.0/native/python/pyjp_char.cpp000066400000000000000000000451141405671516700201550ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "pyjp.h" #include #include "jp_boxedtype.h" #ifdef __cplusplus extern "C" { #endif PyTypeObject *PyJPChar_Type = NULL; struct PyJPChar { PyCompactUnicodeObject m_Obj; char m_Data[4]; } ; #define _PyUnicode_LENGTH(op) (((PyASCIIObject *)(op))->length) #define _PyUnicode_STATE(op) (((PyASCIIObject *)(op))->state) #define _PyUnicode_HASH(op) (((PyASCIIObject *)(op))->hash) #define _PyUnicode_WSTR(op) (((PyASCIIObject*)(op))->wstr) #define _PyUnicode_WSTR_LENGTH(op) (((PyCompactUnicodeObject*)(op))->wstr_length) static Py_UCS4 ord(PyObject *c) { if (PyUnicode_Check(c)) { if (PyUnicode_READY(c) == -1) return -1; if (PyUnicode_GET_LENGTH(c) == 1) return PyUnicode_READ_CHAR(c, 0); } else if (PyBytes_Check(c) && PyBytes_GET_SIZE(c) == 1) return (Py_UCS4) ((unsigned char) *PyBytes_AS_STRING(c)); else if (PyByteArray_Check(c) && PyByteArray_GET_SIZE(c)) return (Py_UCS4) ((unsigned char) *PyByteArray_AS_STRING(c)); return (Py_UCS4) - 1; } static int isNull(JPValue *javaSlot) { if (javaSlot != NULL ) { JPClass *cls = javaSlot->getClass(); if (cls->isPrimitive() || javaSlot->getValue().l != NULL) return 0; } return 1; } static int assertNotNull(JPValue *javaSlot) { if (!isNull(javaSlot)) return 0; PyErr_SetString(PyExc_TypeError, "cast of null pointer"); return 1; } PyObject *PyJPChar_Create(PyTypeObject *type, Py_UCS2 p) { PyJPChar *self = (PyJPChar*) PyJPValue_alloc(type, 0); if (self == 0) return 0; self->m_Data[0] = 0; self->m_Data[1] = 0; self->m_Data[2] = 0; self->m_Data[3] = 0; _PyUnicode_LENGTH(self) = 1; _PyUnicode_HASH(self) = -1; _PyUnicode_STATE(self).kind = PyUnicode_1BYTE_KIND; _PyUnicode_STATE(self).ascii = 0; _PyUnicode_STATE(self).ready = 1; _PyUnicode_STATE(self).interned = 0; _PyUnicode_STATE(self).compact = 1; if (p < 128) { _PyUnicode_STATE(self).ascii = 1; char *data = (char*) (((PyASCIIObject*) self) + 1); data[0] = p; data[1] = 0; } else if (p < 256) { char *data = (char*) ( ((PyCompactUnicodeObject*) self) + 1); data[0] = p; data[1] = 0; _PyUnicode_WSTR_LENGTH(self) = 0; _PyUnicode_WSTR(self) = NULL; self->m_Obj.utf8 = NULL; self->m_Obj.utf8_length = 0; } else { Py_UCS2 *data = (Py_UCS2*) ( ((PyCompactUnicodeObject*) self) + 1); data[0] = p; data[1] = 0; _PyUnicode_STATE(self).kind = PyUnicode_2BYTE_KIND; if (sizeof (wchar_t) == 2) { _PyUnicode_WSTR_LENGTH(self) = 1; _PyUnicode_WSTR(self) = (wchar_t *) data; } else { _PyUnicode_WSTR_LENGTH(self) = 0; _PyUnicode_WSTR(self) = NULL; } self->m_Obj.utf8 = NULL; self->m_Obj.utf8_length = 0; } return (PyObject*) self; } /** This one is just used for initializing so the local copy matches. */ Py_UCS2 fromJPValue(const JPValue & value) { JPClass* cls = value.getClass(); if (cls->isPrimitive()) return (Py_UCS2) (value.getValue().c); JPPrimitiveType* pcls = ((JPBoxedType*) cls)->getPrimitive(); if (value.getValue().l == 0) return (Py_UCS2) - 1; else return (Py_UCS2) (pcls->getValueFromObject(value).getValue().c); } /** Get the value of the char. Does not touch Java. */ Py_UCS2 fromJPChar(PyJPChar *self) { if (_PyUnicode_STATE(self).ascii == 1) { Py_UCS1 *data = (Py_UCS1*) (((PyASCIIObject*) self) + 1); return data[0]; } if (_PyUnicode_STATE(self).kind == PyUnicode_1BYTE_KIND) { Py_UCS1 *data = (Py_UCS1*) ( ((PyCompactUnicodeObject*) self) + 1); return data[0]; } Py_UCS2 *data = (Py_UCS2*) ( ((PyCompactUnicodeObject*) self) + 1); return data[0]; } static PyObject * PyJPChar_new(PyTypeObject *type, PyObject *pyargs, PyObject * kwargs) { JP_PY_TRY("PyJPChar_new"); // Get the Java class from the type. JPClass *cls = PyJPClass_getJPClass((PyObject*) type); if (cls == NULL) { // GCOVR_EXCL_START PyErr_SetString(PyExc_TypeError, "Java class type is incorrect"); return 0; } // GCOVR_EXCL_STOP JPContext *context = PyJPModule_getContext(); // Create an instance (this may fail) JPJavaFrame frame = JPJavaFrame::outer(context); if (PyTuple_Size(pyargs) != 1) { PyErr_SetString(PyExc_TypeError, "Java chars require one argument"); return 0; } JPValue jv; PyObject *in = PyTuple_GetItem(pyargs, 0); Py_UCS4 cv = ord(in); if (cv != (Py_UCS4) - 1) { JPPyObject v = JPPyObject::call(PyLong_FromLong(cv)); JPPyObject args0 = JPPyObject::call(PyTuple_Pack(1, v.get())); JPPyObjectVector args(args0.get()); jv = cls->newInstance(frame, args); } else if (PyIndex_Check(in)) { JPPyObjectVector args(pyargs); jv = cls->newInstance(frame, args); } else if (PyFloat_Check(in)) { JPPyObject v = JPPyObject::call(PyNumber_Long(in)); JPPyObject args0 = JPPyObject::call(PyTuple_Pack(1, v.get())); JPPyObjectVector args(args0.get()); jv = cls->newInstance(frame, args); } else { // This is not strictly true as we can cast a float to a char PyErr_SetString(PyExc_TypeError, "Java require index or str with length 1"); return 0; } PyObject *self = PyJPChar_Create(type, fromJPValue(jv)); JP_PY_CHECK(); PyJPValue_assignJavaSlot(frame, self, jv); return self; JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } static PyObject *PyJPChar_str(PyJPChar *self) { JP_PY_TRY("PyJPChar_str"); PyJPModule_getContext(); // Check that JVM is running JPValue *javaSlot = PyJPValue_getJavaSlot((PyObject*) self); if (javaSlot == NULL) { // GCOVR_EXCL_START // A slot is required PyErr_SetString(PyExc_TypeError, "Java slot is not set on Java char"); return 0; } // GCOVR_EXCL_STOP if (isNull(javaSlot)) return JPPyString::fromStringUTF8("None").keep(); return PyUnicode_FromOrdinal(fromJPChar(self)); JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } static PyObject *PyJPChar_repr(PyJPChar *self) { JP_PY_TRY("PyJPChar_repr"); PyJPModule_getContext(); // Check that JVM is running JPValue *javaSlot = PyJPValue_getJavaSlot((PyObject*) self); if (javaSlot == NULL) { // GCOVR_EXCL_START // A slot is required PyErr_SetString(PyExc_TypeError, "Java slot is not set on Java char"); return 0; } // GCOVR_EXCL_STOP if (isNull(javaSlot)) return JPPyString::fromStringUTF8("None").keep(); return PyUnicode_Type.tp_repr((PyObject*) self); JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } static PyObject *PyJPChar_index(PyJPChar *self) { JP_PY_TRY("PyJPChar_index"); PyJPModule_getContext(); // Check that JVM is running JPValue *javaSlot = PyJPValue_getJavaSlot((PyObject*) self); if (assertNotNull(javaSlot)) return 0; return PyLong_FromLong(fromJPChar(self)); JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } static PyObject *PyJPChar_float(PyJPChar *self) { JP_PY_TRY("PyJPChar_float"); PyJPModule_getContext(); // Check that JVM is running JPValue *javaSlot = PyJPValue_getJavaSlot((PyObject*) self); if (assertNotNull(javaSlot)) return 0; return PyFloat_FromDouble(fromJPChar(self)); JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } static PyObject *PyJPChar_abs(PyJPChar *self) { JP_PY_TRY("PyJPChar_nop"); PyJPModule_getContext(); // Check that JVM is running JPValue *javaSlot = PyJPValue_getJavaSlot((PyObject*) self); if (assertNotNull(javaSlot)) return 0; // Promote to int as per Java rules JPPyObject v = JPPyObject::call(PyLong_FromLong(fromJPChar(self))); return PyLong_Type.tp_as_number->nb_absolute(v.get()); JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } static Py_ssize_t PyJPChar_len(PyJPChar *self) { JP_PY_TRY("PyJPChar_nop"); PyJPModule_getContext(); // Check that JVM is running JPValue *javaSlot = PyJPValue_getJavaSlot((PyObject*) self); if (assertNotNull(javaSlot)) return -1; return 1; JP_PY_CATCH(-1); // GCOVR_EXCL_LINE } static PyObject *PyJPChar_and(PyJPChar *self, PyObject *other) { JP_PY_TRY("PyJPChar_and"); PyJPModule_getContext(); // Check that JVM is running JPValue *javaSlot = PyJPValue_getJavaSlot((PyObject*) self); if (assertNotNull(javaSlot)) return 0; // Promote to int as per Java rules JPPyObject v = JPPyObject::call(PyLong_FromLong(fromJPChar(self))); return PyNumber_And(v.get(), other); JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } static PyObject *PyJPChar_or(PyJPChar *self, PyObject *other) { JP_PY_TRY("PyJPChar_or"); PyJPModule_getContext(); // Check that JVM is running JPValue *javaSlot = PyJPValue_getJavaSlot((PyObject*) self); if (assertNotNull(javaSlot)) return 0; // Promote to int as per Java rules JPPyObject v = JPPyObject::call(PyLong_FromLong(fromJPChar(self))); return PyNumber_Or(v.get(), other); JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } static PyObject *PyJPChar_xor(PyJPChar *self, PyObject *other) { JP_PY_TRY("PyJPChar_xor"); PyJPModule_getContext(); // Check that JVM is running JPValue *javaSlot = PyJPValue_getJavaSlot((PyObject*) self); if (assertNotNull(javaSlot)) return 0; // Promote to int as per Java rules JPPyObject v = JPPyObject::call(PyLong_FromLong(fromJPChar(self))); return PyNumber_Xor(v.get(), other); JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } static PyObject *PyJPChar_add(PyJPChar *self, PyObject *other) { JP_PY_TRY("PyJPChar_add"); PyJPModule_getContext(); // Check that JVM is running JPValue *javaSlot = PyJPValue_getJavaSlot((PyObject*) self); if (assertNotNull(javaSlot)) return 0; if (PyUnicode_Check(other)) return PyUnicode_Type.tp_as_number->nb_add((PyObject*) self, other); // Promote to int as per Java rules JPPyObject v = JPPyObject::call(PyLong_FromLong(fromJPChar(self))); return PyNumber_Add(v.get(), other); JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } static PyObject *PyJPChar_subtract(PyJPChar *self, PyObject *other) { JP_PY_TRY("PyJPChar_subtract"); PyJPModule_getContext(); // Check that JVM is running JPValue *javaSlot = PyJPValue_getJavaSlot((PyObject*) self); if (assertNotNull(javaSlot)) return 0; // Promote to int as per Java rules JPPyObject v = JPPyObject::call(PyLong_FromLong(fromJPChar(self))); return PyNumber_Subtract(v.get(), other); JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } static PyObject *PyJPChar_mult(PyJPChar *self, PyObject *other) { JP_PY_TRY("PyJPChar_mult"); PyJPModule_getContext(); // Check that JVM is running JPValue *javaSlot = PyJPValue_getJavaSlot((PyObject*) self); if (assertNotNull(javaSlot)) return 0; // Promote to int as per Java rules JPPyObject v = JPPyObject::call(PyLong_FromLong(fromJPChar(self))); return PyNumber_Multiply(v.get(), other); JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } static PyObject *PyJPChar_rshift(PyJPChar *self, PyObject *other) { JP_PY_TRY("PyJPChar_rshift"); PyJPModule_getContext(); // Check that JVM is running JPValue *javaSlot = PyJPValue_getJavaSlot((PyObject*) self); if (assertNotNull(javaSlot)) return 0; // Promote to int as per Java rules JPPyObject v = JPPyObject::call(PyLong_FromLong(fromJPChar(self))); return PyNumber_Rshift(v.get(), other); JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } static PyObject *PyJPChar_lshift(PyJPChar *self, PyObject *other) { JP_PY_TRY("PyJPChar_lshift"); PyJPModule_getContext(); // Check that JVM is running JPValue *javaSlot = PyJPValue_getJavaSlot((PyObject*) self); if (assertNotNull(javaSlot)) return 0; // Promote to int as per Java rules JPPyObject v = JPPyObject::call(PyLong_FromLong(fromJPChar(self))); return PyNumber_Lshift(v.get(), other); JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } static PyObject *PyJPChar_floordiv(PyObject *self, PyObject *other) { JP_PY_TRY("PyJPChar_floordiv"); PyJPModule_getContext(); // Check that JVM is running JPValue *javaSlot = PyJPValue_getJavaSlot(self); if (javaSlot == NULL) { javaSlot = PyJPValue_getJavaSlot(other); if (assertNotNull(javaSlot)) return 0; JPPyObject v = JPPyObject::call(PyLong_FromLong(fromJPChar((PyJPChar*) other))); return PyNumber_FloorDivide(self, v.get()); } if (assertNotNull(javaSlot)) return 0; // Promote to int as per Java rules JPPyObject v = JPPyObject::call(PyLong_FromLong(fromJPChar((PyJPChar*) self))); return PyNumber_FloorDivide(v.get(), other); JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } static PyObject *PyJPChar_divmod(PyObject *self, PyObject *other) { JP_PY_TRY("PyJPChar_divmod"); PyJPModule_getContext(); // Check that JVM is running JPValue *javaSlot = PyJPValue_getJavaSlot( self); if (javaSlot == NULL) { javaSlot = PyJPValue_getJavaSlot(other); if (assertNotNull(javaSlot)) return 0; JPPyObject v = JPPyObject::call(PyLong_FromLong(fromJPChar((PyJPChar*) other))); return PyNumber_Divmod(self, v.get()); } if (assertNotNull(javaSlot)) return 0; // Promote to int as per Java rules JPPyObject v = JPPyObject::call(PyLong_FromLong(fromJPChar((PyJPChar*) self))); return PyNumber_Divmod(v.get(), other); JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } static PyObject *PyJPChar_neg(PyJPChar *self) { JP_PY_TRY("PyJPChar_neg"); PyJPModule_getContext(); // Check that JVM is running JPValue *javaSlot = PyJPValue_getJavaSlot((PyObject*) self); if (assertNotNull(javaSlot)) return 0; // Promote to int as per Java rules JPPyObject v = JPPyObject::call(PyLong_FromLong(fromJPChar(self))); return PyNumber_Negative(v.get()); JP_PY_CATCH(0); // GCOVR_EXCL_LINE } static PyObject *PyJPChar_pos(PyJPChar *self) { JP_PY_TRY("PyJPChar_pos"); PyJPModule_getContext(); // Check that JVM is running JPValue *javaSlot = PyJPValue_getJavaSlot((PyObject*) self); if (assertNotNull(javaSlot)) return 0; // Promote to int as per Java rules JPPyObject v = JPPyObject::call(PyLong_FromLong(fromJPChar(self))); return PyNumber_Positive(v.get()); JP_PY_CATCH(0); // GCOVR_EXCL_LINE } static PyObject *PyJPChar_inv(PyJPChar *self) { JP_PY_TRY("PyJPObject_neg"); PyJPModule_getContext(); // Check that JVM is running JPValue *javaSlot = PyJPValue_getJavaSlot((PyObject*) self); if (assertNotNull(javaSlot)) return 0; // Promote to int as per Java rules JPPyObject v = JPPyObject::call(PyLong_FromLong(fromJPChar(self))); return PyNumber_Invert(v.get()); JP_PY_CATCH(0); // GCOVR_EXCL_LINE } static PyObject *PyJPJChar_compare(PyObject *self, PyObject *other, int op) { JP_PY_TRY("PyJPJChar_compare"); PyJPModule_getContext(); // Check that JVM is running JPValue *javaSlot1 = PyJPValue_getJavaSlot(other); JPValue *javaSlot0 = PyJPValue_getJavaSlot(self); if (isNull(javaSlot0)) { if (javaSlot1 != NULL && isNull(javaSlot1)) other = Py_None; if (op == Py_EQ) return PyBool_FromLong(other == Py_None ); if (op == Py_NE) return PyBool_FromLong(other != Py_None); PyObject *out = Py_NotImplemented; Py_INCREF(out); return out; JP_RAISE_PYTHON(); } if (javaSlot1 != NULL && isNull(javaSlot1)) return PyBool_FromLong(op == Py_NE); if (PyUnicode_Check(other)) { // char <=> char // char <=> str return PyUnicode_Type.tp_richcompare(self, other, op); } if (PyFloat_Check(other)) { JPPyObject v = JPPyObject::call(PyLong_FromLong(fromJPChar((PyJPChar*) self))); if (op < 2) op += 4; else if (op > 3) op -= 4; return PyFloat_Type.tp_richcompare(other, v.get(), op); } if (PyNumber_Check(other)) { JPPyObject v = JPPyObject::call(PyLong_FromLong(fromJPChar((PyJPChar*) self))); return PyLong_Type.tp_richcompare(v.get(), other, op); } if (javaSlot1 != NULL) { // char <=> object // object <=> char // object <=> object switch (op) { case Py_EQ: Py_RETURN_FALSE; case Py_NE: Py_RETURN_TRUE; } PyObject *out = Py_NotImplemented; Py_INCREF(out); return out; } PyObject *out = Py_NotImplemented; Py_INCREF(out); return out; JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } static Py_hash_t PyJPChar_hash(PyObject *self) { JP_PY_TRY("PyJPObject_hash"); PyJPModule_getContext(); // Check that JVM is running JPValue *javaSlot = PyJPValue_getJavaSlot(self); if (isNull(javaSlot)) return Py_TYPE(Py_None)->tp_hash(Py_None); return PyUnicode_Type.tp_hash((PyObject*) self); JP_PY_CATCH(0); // GCOVR_EXCL_LINE } static int PyJPChar_bool(PyJPChar *self) { JP_PY_TRY("PyJPObject_bool"); PyJPModule_getContext(); // Check that JVM is running JPValue *javaSlot = PyJPValue_getJavaSlot((PyObject*) self); if (isNull(javaSlot)) return 0; return fromJPChar(self) != 0; JP_PY_CATCH(0); // GCOVR_EXCL_LINE } static PyMethodDef charMethods[] = { // {"thing", (PyCFunction) PyJPMethod_matchReport, METH_VARARGS, ""}, {NULL}, }; struct PyGetSetDef charGetSet[] = { // {"thing", (getter) PyJPMethod_getSelf, NULL, NULL, NULL}, {NULL}, }; static PyType_Slot charSlots[] = { {Py_tp_new, (void*) PyJPChar_new}, {Py_tp_methods, (void*) charMethods}, {Py_tp_getset, (void*) charGetSet}, {Py_tp_str, (void*) PyJPChar_str}, {Py_tp_repr, (void*) PyJPChar_repr}, {Py_nb_index, (void*) PyJPChar_index}, #if PY_VERSION_HEX<0x03080000 {Py_nb_int, (void*) PyJPChar_index}, #endif {Py_nb_float, (void*) PyJPChar_float}, {Py_nb_absolute, (void*) PyJPChar_abs}, {Py_nb_and, (void*) PyJPChar_and}, {Py_nb_or, (void*) PyJPChar_or}, {Py_nb_xor, (void*) PyJPChar_xor}, {Py_nb_add, (void*) PyJPChar_add}, {Py_nb_subtract, (void*) PyJPChar_subtract}, {Py_nb_multiply, (void*) PyJPChar_mult}, {Py_nb_rshift, (void*) PyJPChar_rshift}, {Py_nb_lshift, (void*) PyJPChar_lshift}, {Py_tp_richcompare, (void*) PyJPJChar_compare}, {Py_tp_hash, (void*) PyJPChar_hash}, {Py_nb_bool, (void*) PyJPChar_bool}, {Py_nb_negative, (void*) PyJPChar_neg}, {Py_nb_positive, (void*) PyJPChar_pos}, {Py_nb_invert, (void*) PyJPChar_inv}, {Py_nb_floor_divide, (void*) PyJPChar_floordiv}, {Py_nb_divmod, (void*) PyJPChar_divmod}, {Py_tp_getattro, (void*) PyJPValue_getattro}, {Py_tp_setattro, (void*) PyJPValue_setattro}, { Py_sq_length, (void*) PyJPChar_len}, {0} }; static PyType_Spec charSpec = { "_jpype._JChar", sizeof (PyJPChar), 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // | Py_TPFLAGS_HAVE_GC, charSlots }; #ifdef __cplusplus } #endif void PyJPChar_initType(PyObject* module) { // We will inherit from str and JObject PyObject *bases = PyTuple_Pack(2, &PyUnicode_Type, PyJPObject_Type); PyJPChar_Type = (PyTypeObject*) PyJPClass_FromSpecWithBases(&charSpec, bases); Py_DECREF(bases); JP_PY_CHECK(); // GCOVR_EXCL_LINE PyModule_AddObject(module, "_JChar", (PyObject*) PyJPChar_Type); JP_PY_CHECK(); // GCOVR_EXCL_LINE } jpype-1.3.0/native/python/pyjp_class.cpp000066400000000000000000001042531405671516700203450ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include #include #include #include #include "jpype.h" #include "pyjp.h" #include "jp_array.h" #include "jp_arrayclass.h" #include "jp_boxedtype.h" #include "jp_field.h" #include "jp_method.h" #include "jp_methoddispatch.h" #include "jp_primitive_accessor.h" struct PyJPClass { PyHeapTypeObject ht_type; JPClass *m_Class; PyObject *m_Doc; } ; PyObject* PyJPClassMagic = NULL; #ifdef __cplusplus extern "C" { #endif int PyJPClass_Check(PyObject* obj) { return PyJP_IsInstanceSingle(obj, PyJPClass_Type); } static int PyJPClass_traverse(PyJPClass *self, visitproc visit, void *arg) { Py_VISIT(self->m_Doc); return 0; } static int PyJPClass_clear(PyJPClass *self) { Py_CLEAR(self->m_Doc); return 0; } PyObject *PyJPClass_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { JP_PY_TRY("PyJPClass_new"); if (PyTuple_Size(args) != 3) JP_RAISE(PyExc_TypeError, "Java class meta required 3 arguments"); JP_BLOCK("PyJPClass_new::verify") { // Watch for final classes PyObject *bases = PyTuple_GetItem(args, 1); Py_ssize_t len = PyTuple_Size(bases); for (Py_ssize_t i = 0; i < len; ++i) { PyObject *item = PyTuple_GetItem(bases, i); JPClass *cls = PyJPClass_getJPClass(item); if (cls != NULL && cls->isFinal()) { PyErr_Format(PyExc_TypeError, "Cannot extend final class '%s'", ((PyTypeObject*) item)->tp_name); } } } int magic = 0; if (kwargs == PyJPClassMagic || (kwargs != NULL && PyDict_GetItemString(kwargs, "internal") != 0)) { magic = 1; kwargs = NULL; } if (magic == 0) { PyErr_Format(PyExc_TypeError, "Java classes cannot be extended in Python"); return 0; } PyTypeObject *typenew = (PyTypeObject*) PyType_Type.tp_new(type, args, kwargs); // GCOVR_EXCL_START // Sanity checks. Not testable if (typenew == 0) return NULL; if (typenew->tp_finalize != NULL && typenew->tp_finalize != (destructor) PyJPValue_finalize) { Py_DECREF(typenew); PyErr_SetString(PyExc_TypeError, "finalizer conflict"); return NULL; } // This sanity check is trigger if the user attempts to build their own // type wrapper with a __del__ method defined. It is hard to trigger. if (typenew->tp_alloc != (allocfunc) PyJPValue_alloc && typenew->tp_alloc != PyBaseObject_Type.tp_alloc) { Py_DECREF(typenew); PyErr_SetString(PyExc_TypeError, "alloc conflict"); return NULL; } // GCOVR_EXCL_STOP typenew->tp_alloc = (allocfunc) PyJPValue_alloc; typenew->tp_finalize = (destructor) PyJPValue_finalize; if (PyObject_IsSubclass((PyObject*) typenew, (PyObject*) PyJPException_Type)) { typenew->tp_new = PyJPException_Type->tp_new; } ((PyJPClass*) typenew)->m_Doc = NULL; return (PyObject*) typenew; JP_PY_CATCH(NULL); } PyObject* examine(PyObject *module, PyObject *other); PyObject* PyJPClass_FromSpecWithBases(PyType_Spec *spec, PyObject *bases) { JP_PY_TRY("PyJPClass_FromSpecWithBases"); // Python lacks a FromSpecWithMeta so we are going to have to fake it here. PyTypeObject* type = (PyTypeObject*) PyJPClass_Type->tp_alloc(PyJPClass_Type, 0); PyHeapTypeObject* heap = (PyHeapTypeObject*) type; type->tp_flags = spec->flags | Py_TPFLAGS_HEAPTYPE; type->tp_name = spec->name; const char *s = strrchr(spec->name, '.'); if (s == NULL) s = spec->name; else s++; heap->ht_qualname = PyUnicode_FromString(s); heap->ht_name = heap->ht_qualname; Py_INCREF(heap->ht_name); if (bases == NULL) type->tp_bases = PyTuple_Pack(1, (PyObject*) & PyBaseObject_Type); else { type->tp_bases = bases; Py_INCREF(bases); } type->tp_base = (PyTypeObject*) PyTuple_GetItem(type->tp_bases, 0); Py_INCREF(type->tp_base); type->tp_as_async = &heap->as_async; type->tp_as_buffer = &heap->as_buffer; type->tp_as_mapping = &heap->as_mapping; type->tp_as_number = &heap->as_number; type->tp_as_sequence = &heap->as_sequence; type->tp_basicsize = spec->basicsize; if (spec->basicsize == 0) type->tp_basicsize = type->tp_base->tp_basicsize; type->tp_itemsize = spec->itemsize; if (spec->itemsize == 0) type->tp_itemsize = type->tp_base->tp_itemsize; type->tp_alloc = PyJPValue_alloc; type->tp_free = PyJPValue_free; type->tp_finalize = (destructor) PyJPValue_finalize; for (PyType_Slot* slot = spec->slots; slot->slot; slot++) { switch (slot->slot) { case Py_tp_free: type->tp_free = (freefunc) slot->pfunc; break; case Py_tp_new: type->tp_new = (newfunc) slot->pfunc; break; case Py_tp_init: type->tp_init = (initproc) slot->pfunc; break; case Py_tp_getattro: type->tp_getattro = (getattrofunc) slot->pfunc; break; case Py_tp_setattro: type->tp_setattro = (setattrofunc) slot->pfunc; break; case Py_tp_dealloc: type->tp_dealloc = (destructor) slot->pfunc; break; case Py_tp_str: type->tp_str = (reprfunc) slot->pfunc; break; case Py_tp_repr: type->tp_repr = (reprfunc) slot->pfunc; break; case Py_tp_methods: type->tp_methods = (PyMethodDef*) slot->pfunc; break; case Py_sq_item: heap->as_sequence.sq_item = (ssizeargfunc) slot->pfunc; break; case Py_sq_length: heap->as_sequence.sq_length = (lenfunc) slot->pfunc; break; case Py_mp_ass_subscript: heap->as_mapping.mp_ass_subscript = (objobjargproc) slot->pfunc; break; case Py_tp_hash: type->tp_hash = (hashfunc) slot->pfunc; break; case Py_nb_int: heap->as_number.nb_int = (unaryfunc) slot->pfunc; break; case Py_nb_float: heap->as_number.nb_float = (unaryfunc) slot->pfunc; break; case Py_tp_richcompare: type->tp_richcompare = (richcmpfunc) slot->pfunc; break; case Py_mp_subscript: heap->as_mapping.mp_subscript = (binaryfunc) slot->pfunc; break; case Py_nb_index: heap->as_number.nb_index = (unaryfunc) slot->pfunc; break; case Py_nb_absolute: heap->as_number.nb_absolute = (unaryfunc) slot->pfunc; break; case Py_nb_and: heap->as_number.nb_and = (binaryfunc) slot->pfunc; break; case Py_nb_or: heap->as_number.nb_or = (binaryfunc) slot->pfunc; break; case Py_nb_xor: heap->as_number.nb_xor = (binaryfunc) slot->pfunc; break; case Py_nb_add: heap->as_number.nb_add = (binaryfunc) slot->pfunc; break; case Py_nb_subtract: heap->as_number.nb_subtract = (binaryfunc) slot->pfunc; break; case Py_nb_multiply: heap->as_number.nb_multiply = (binaryfunc) slot->pfunc; break; case Py_nb_rshift: heap->as_number.nb_rshift = (binaryfunc) slot->pfunc; break; case Py_nb_lshift: heap->as_number.nb_lshift = (binaryfunc) slot->pfunc; break; case Py_nb_negative: heap->as_number.nb_negative = (unaryfunc) slot->pfunc; break; case Py_nb_bool: heap->as_number.nb_bool = (inquiry) slot->pfunc; break; case Py_nb_invert: heap->as_number.nb_invert = (unaryfunc) slot->pfunc; break; case Py_nb_positive: heap->as_number.nb_positive = (unaryfunc) slot->pfunc; break; case Py_nb_floor_divide: heap->as_number.nb_floor_divide = (binaryfunc) slot->pfunc; break; case Py_nb_divmod: heap->as_number.nb_divmod = (binaryfunc) slot->pfunc; break; case Py_tp_getset: type->tp_getset = (PyGetSetDef*) slot->pfunc; break; // GCOVR_EXCL_START default: PyErr_Format(PyExc_TypeError, "slot %d not implemented", slot->slot); JP_RAISE_PYTHON(); // GCOVR_EXCL_STOP } } // GC objects are required to implement clear and traverse, this is a // safety check to make sure we implemented all properly. This error should // never happen in production code. if (PyType_IS_GC(type) && ( type->tp_traverse==NULL || type->tp_clear==NULL)) { PyErr_Format(PyExc_TypeError, "GC requirements failed for %s", spec->name); JP_RAISE_PYTHON(); } PyType_Ready(type); PyDict_SetItemString(type->tp_dict, "__module__", PyUnicode_FromString("_jpype")); return (PyObject*) type; JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } int PyJPClass_init(PyObject *self, PyObject *args, PyObject *kwargs) { JP_PY_TRY("PyJPClass_init"); if (PyTuple_Size(args) == 1) return 0; // Set the host object PyObject *name = NULL; PyObject *bases = NULL; PyObject *members = NULL; if (!PyArg_ParseTuple(args, "OOO", &name, &bases, &members)) return -1; // Check that all types are Java types if (!PyTuple_Check(bases)) { PyErr_SetString(PyExc_TypeError, "Bases must be a tuple"); return -1; } for (int i = 0; i < PyTuple_Size(bases); ++i) { if (!PyJPClass_Check(PyTuple_GetItem(bases, i))) { PyErr_SetString(PyExc_TypeError, "All bases must be Java types"); return -1; } } // Call the type init int rc = PyType_Type.tp_init(self, args, NULL); if (rc == -1) return rc; // GCOVR_EXCL_LINE no clue how to trigger this one return rc; JP_PY_CATCH(-1); } static void PyJPClass_dealloc(PyJPClass *self) { JP_PY_TRY("PyJPClass_dealloc"); PyObject_GC_UnTrack(self); PyJPClass_clear(self); Py_TYPE(self)->tp_free(self); JP_PY_CATCH_NONE(); // GCOVR_EXCL_LINE } PyObject* PyJPClass_mro(PyTypeObject *self) { Py_ssize_t sz = PySequence_Size(self->tp_bases); std::list bases; bases.push_back((PyObject*) self); // Merge together all bases std::list out; for (std::list::iterator iter = bases.begin(); iter != bases.end(); ++iter) { PyObject *l = ((PyTypeObject*) * iter)->tp_bases; sz = PySequence_Size(l); for (Py_ssize_t i = 0; i < sz; ++i) { PyObject *obj = PyTuple_GetItem(l, i); bool found = (std::find(bases.begin(), bases.end(), obj) != bases.end()); if (!found) { bases.push_back(obj); } } } while (!bases.empty()) { PyObject* front = bases.front(); bases.pop_front(); for (std::list::iterator iter = bases.begin(); iter != bases.end(); ++iter) { if (PySequence_Contains(((PyTypeObject*) * iter)->tp_bases, front)) { bases.push_back(front); front = NULL; break; } } if (front != NULL) { out.push_back(front); PyObject* next = (PyObject*) ((PyTypeObject*) front)->tp_base; if (next) { bases.remove(next); bases.push_front(next); } } } PyObject *obj = PyTuple_New(out.size()); int j = 0; for (std::list::iterator iter = out.begin(); iter != out.end(); ++iter) { Py_INCREF(*iter); PyTuple_SetItem(obj, j++, *iter); } return obj; } PyObject *PyJPClass_getattro(PyObject *obj, PyObject *name) { JP_PY_TRY("PyJPClass_getattro"); if (!PyUnicode_Check(name)) { PyErr_Format(PyExc_TypeError, "attribute name must be string, not '%.200s'", Py_TYPE(name)->tp_name); return NULL; } // Private members are accessed directly PyObject* pyattr = PyType_Type.tp_getattro(obj, name); if (pyattr == NULL) return NULL; JPPyObject attr = JPPyObject::claim(pyattr); // Private members go regardless if (PyUnicode_GetLength(name) && PyUnicode_ReadChar(name, 0) == '_') return attr.keep(); // Methods if (Py_TYPE(attr.get()) == PyJPMethod_Type) return attr.keep(); // Don't allow properties to be rewritten if (!PyObject_IsInstance(attr.get(), (PyObject*) & PyProperty_Type)) return attr.keep(); const char *name_str = PyUnicode_AsUTF8(name); PyErr_Format(PyExc_AttributeError, "Field '%s' is static", name_str); return NULL; JP_PY_CATCH(NULL); } int PyJPClass_setattro(PyObject *self, PyObject *attr_name, PyObject *v) { JP_PY_TRY("PyJPClass_setattro"); PyJPModule_getContext(); if (!PyUnicode_Check(attr_name)) { PyErr_Format(PyExc_TypeError, "attribute name must be string, not '%.200s'", attr_name->ob_type->tp_name); return -1; } // Private members are accessed directly if (PyUnicode_GetLength(attr_name) && PyUnicode_ReadChar(attr_name, 0) == '_') return PyType_Type.tp_setattro(self, attr_name, v); JPPyObject f = JPPyObject::accept(PyJP_GetAttrDescriptor((PyTypeObject*) self, attr_name)); if (f.isNull()) { const char *name_str = PyUnicode_AsUTF8(attr_name); PyErr_Format(PyExc_AttributeError, "Field '%s' is not found", name_str); return -1; } descrsetfunc desc = Py_TYPE(f.get())->tp_descr_set; if (desc != NULL) return desc(f.get(), self, v); // Not a descriptor const char *name_str = PyUnicode_AsUTF8(attr_name); PyErr_Format(PyExc_AttributeError, "Static field '%s' is not settable on Java '%s' object", name_str, ((PyTypeObject*) self)->tp_name); return -1; JP_PY_CATCH(-1); } PyObject* PyJPClass_subclasscheck(PyTypeObject *type, PyTypeObject *test) { JP_PY_TRY("PyJPClass_subclasscheck"); if (test == type) Py_RETURN_TRUE; // GCOVR_EXCL_START // This is triggered only if the user asks for isInstance when the // JVM is shutdown. It should not happen in normal operations. if (!JPContext_global->isRunning()) { if ((PyObject*) type == _JObject) return PyBool_FromLong(PyJP_IsSubClassSingle(PyJPObject_Type, test)); return PyBool_FromLong(PyJP_IsSubClassSingle(type, test)); } // GCOVR_EXCL_STOP JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); // Check for class inheritance first JPClass *testClass = PyJPClass_getJPClass((PyObject*) test); JPClass *typeClass = PyJPClass_getJPClass((PyObject*) type); if (testClass == NULL) Py_RETURN_FALSE; if (testClass == typeClass) Py_RETURN_TRUE; if (typeClass != NULL) { if (typeClass->isPrimitive()) Py_RETURN_FALSE; bool b = frame.IsAssignableFrom(testClass->getJavaClass(), typeClass->getJavaClass()) != 0; return PyBool_FromLong(b); } // Otherwise check for special cases if ((PyObject*) type == _JInterface) return PyBool_FromLong(testClass->isInterface()); if ((PyObject*) type == _JObject) return PyBool_FromLong(!testClass->isPrimitive()); if ((PyObject*) type == _JArray) return PyBool_FromLong(testClass->isArray()); if ((PyObject*) type == _JException) return PyBool_FromLong(testClass->isThrowable()); PyObject* mro1 = test->tp_mro; Py_ssize_t n1 = PyTuple_Size(mro1); for (int i = 0; i < n1; ++i) { if (PyTuple_GetItem(mro1, i) == (PyObject*) type) Py_RETURN_TRUE; } Py_RETURN_FALSE; JP_PY_CATCH(NULL); } static PyObject *PyJPClass_class(PyObject *self, PyObject *closure) { JP_PY_TRY("PyJPClass_class"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); JPValue* javaSlot = PyJPValue_getJavaSlot(self); if (javaSlot == NULL) { PyErr_SetString(PyExc_AttributeError, "Java slot is null"); return NULL; } return javaSlot->getClass()->convertToPythonObject(frame, javaSlot->getValue(), false).keep(); JP_PY_CATCH(NULL); } static int PyJPClass_setClass(PyObject *self, PyObject *type, PyObject *closure) { JP_PY_TRY("PyJPClass_setClass", self); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); JPValue* javaSlot = PyJPValue_getJavaSlot(type); if (javaSlot == NULL || javaSlot->getClass() != context->_java_lang_Class) { PyErr_SetString(PyExc_TypeError, "Java class instance is required"); return -1; } if (PyJPValue_isSetJavaSlot(self)) { PyErr_SetString(PyExc_AttributeError, "Java class can't be set"); return -1; } PyJPValue_assignJavaSlot(frame, self, *javaSlot); JPClass* cls = frame.findClass((jclass) javaSlot->getJavaObject()); JP_TRACE("Set host", cls, javaSlot->getClass()->getCanonicalName().c_str()); if (cls->getHost() == NULL) cls->setHost(self); ((PyJPClass*) self)->m_Class = cls; return 0; JP_PY_CATCH(-1); } static PyObject *PyJPClass_hints(PyJPClass *self, PyObject *closure) { JP_PY_TRY("PyJPClass_hints"); PyJPModule_getContext(); JPPyObject hints = JPPyObject::use(self->m_Class->getHints()); if (hints.get() == NULL) Py_RETURN_NONE; // GCOVR_EXCL_LINE only triggered if JClassPost failed if (PyObject_HasAttrString((PyObject*) self, "returns") == 1) return hints.keep(); // Copy in info. JPConversionInfo info; JPPyObject ret = JPPyObject::call(PyList_New(0)); JPPyObject implicit = JPPyObject::call(PyList_New(0)); JPPyObject attribs = JPPyObject::call(PyList_New(0)); JPPyObject exact = JPPyObject::call(PyList_New(0)); JPPyObject expl = JPPyObject::call(PyList_New(0)); JPPyObject none = JPPyObject::call(PyList_New(0)); info.ret = ret.get(); info.implicit = implicit.get(); info.attributes = attribs.get(); info.exact = exact.get(); info.expl = expl.get(); info.none = none.get(); self->m_Class->getConversionInfo(info); PyObject_SetAttrString(hints.get(), "returns", ret.get()); PyObject_SetAttrString(hints.get(), "implicit", implicit.get()); PyObject_SetAttrString(hints.get(), "exact", exact.get()); PyObject_SetAttrString(hints.get(), "explicit", expl.get()); PyObject_SetAttrString(hints.get(), "none", none.get()); PyObject_SetAttrString(hints.get(), "attributes", attribs.get()); return hints.keep(); JP_PY_CATCH(NULL); } static int PyJPClass_setHints(PyObject *self, PyObject *value, PyObject *closure) { JP_PY_TRY("PyJPClass_setHints", self); PyJPModule_getContext(); PyJPClass *cls = (PyJPClass*) self; PyObject *hints = cls->m_Class->getHints(); if (hints != NULL) { PyErr_SetString(PyExc_AttributeError, "_hints can't be set"); return -1; } cls->m_Class->setHints(value); return 0; JP_PY_CATCH(-1); } PyObject* PyJPClass_instancecheck(PyTypeObject *self, PyObject *test) { // JInterface is a meta if ((PyObject*) self == _JInterface) { JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); JPClass *testClass = PyJPClass_getJPClass((PyObject*) test); return PyBool_FromLong(testClass != NULL && testClass->isInterface()); } if ((PyObject*) self == _JException) { JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); JPClass *testClass = PyJPClass_getJPClass((PyObject*) test); if (testClass) return PyBool_FromLong(testClass->isThrowable()); } return PyJPClass_subclasscheck(self, Py_TYPE(test)); } static PyObject *PyJPClass_canCast(PyJPClass *self, PyObject *other) { JP_PY_TRY("PyJPClass_canCast"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); JPClass *cls = self->m_Class; // Test the conversion JPMatch match(&frame, other); cls->findJavaConversion(match); // Report to user return PyBool_FromLong(match.type == JPMatch::_exact || match.type == JPMatch::_implicit); JP_PY_CATCH(NULL); } // Added for auditing static PyObject *PyJPClass_canConvertToJava(PyJPClass *self, PyObject *other) { JP_PY_TRY("PyJPClass_canConvertToJava"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); JPClass *cls = self->m_Class; // Test the conversion JPMatch match(&frame, other); cls->findJavaConversion(match); // Report to user if (match.type == JPMatch::_none) return JPPyString::fromStringUTF8("none").keep(); if (match.type == JPMatch::_explicit) return JPPyString::fromStringUTF8("explicit").keep(); if (match.type == JPMatch::_implicit) return JPPyString::fromStringUTF8("implicit").keep(); if (match.type == JPMatch::_exact) return JPPyString::fromStringUTF8("exact").keep(); // Not sure how this could happen Py_RETURN_NONE; // GCOVR_EXCL_LINE JP_PY_CATCH(NULL); } // Return true if the slice is all indices static bool PySlice_CheckFull(PyObject *item) { if (!PySlice_Check(item)) return false; Py_ssize_t start, stop, step; #if PY_VERSION_HEX<0x03060100 int rc = PySlice_GetIndices(item, 0x7fffffff, &start, &stop, &step); return (rc == 0)&&(start == 0)&&(step == 1)&&((int) stop == 0x7fffffff); #elif defined(ANDROID) int rc = PySlice_Unpack(item, &start, &stop, &step); return (rc == 0)&&(start == 0)&&(step == 1)&&((int) stop >= 0x7fffffff); #else int rc = PySlice_Unpack(item, &start, &stop, &step); return (rc == 0)&&(start == 0)&&(step == 1)&&((int) stop == -1); #endif } static PyObject *PyJPClass_array(PyJPClass *self, PyObject *item) { JP_PY_TRY("PyJPClass_array"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); if (PyIndex_Check(item)) { long sz = PyLong_AsLong(item); JPArrayClass *cls = (JPArrayClass*) self->m_Class->newArrayType(frame, 1); JPValue v = cls->newArray(frame, sz); return cls->convertToPythonObject(frame, v.getValue(), true).keep(); } if (PySlice_Check(item)) { if (PySlice_CheckFull(item)) { JPClass *cls = self->m_Class->newArrayType(frame, 1); return PyJPClass_create(frame, cls).keep(); } PyErr_Format(PyExc_TypeError, "Bad array specification on slice"); return NULL; } if (PyTuple_Check(item)) { Py_ssize_t dims = PyTuple_Size(item); Py_ssize_t i = 0; Py_ssize_t defined = 0; Py_ssize_t undefined = 0; std::vector sz; for (; i < dims; ++i) { PyObject* t = PyTuple_GetItem(item, i); if (PyIndex_Check(t) && PyLong_AsLong(t) > 0) { defined++; sz.push_back(PyLong_AsLong(t)); } else break; } for (; i < dims; ++i) if (PySlice_CheckFull(PyTuple_GetItem(item, i))) undefined++; else break; if (defined + undefined != dims) { PyErr_SetString(PyExc_TypeError, "Invalid array definition"); return NULL; } // Get the type JPClass *cls; if (undefined > 0) cls = self->m_Class->newArrayType(frame, undefined); else cls = self->m_Class; // If no dimensions were defined then just return the type if (defined == 0) return PyJPClass_create(frame, cls).keep(); // Otherwise create an array jintArray u = frame.NewIntArray(defined); JPPrimitiveArrayAccessor accessor(frame, u, &JPJavaFrame::GetIntArrayElements, &JPJavaFrame::ReleaseIntArrayElements); for (size_t j = 0; j < sz.size(); ++j) accessor.get()[j] = sz[j]; accessor.commit(); jvalue v; v.l = frame.newArrayInstance(cls->getJavaClass(), u); return context->_java_lang_Object->convertToPythonObject(frame, v, false).keep(); } PyErr_Format(PyExc_TypeError, "Bad array specification"); JP_PY_CATCH(NULL); } static PyObject *PyJPClass_cast(PyJPClass *self, PyObject *other) { JP_PY_TRY("PyJPClass_cast"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); JPClass *type = self->m_Class; JPValue *val = PyJPValue_getJavaSlot(other); // Cast on non-Java if (val == NULL || val->getClass()->isPrimitive()) { JPMatch match(&frame, other); type->findJavaConversion(match); // Otherwise, see if we can convert it if (match.type == JPMatch::_none) { PyErr_Format(PyExc_TypeError, "Unable to cast '%s' to java type '%s'", Py_TYPE(other)->tp_name, type->getCanonicalName().c_str() ); return NULL; } jvalue v = match.convert(); return type->convertToPythonObject(frame, v, true).keep(); } // Cast on java object // if (!type->isSubTypeOf(val->getClass())) jobject obj = val->getJavaObject(); if (obj == NULL) { jvalue v; v.l = NULL; return type->convertToPythonObject(frame, v, true).keep(); } JPClass *otherClass = frame.findClassForObject(obj); if (otherClass == NULL) { return type->convertToPythonObject(frame, val->getValue(), true).keep(); } if (!otherClass->isAssignableFrom(frame, type)) { PyErr_Format(PyExc_TypeError, "Unable to cast '%s' to java type '%s'", otherClass->getCanonicalName().c_str(), type->getCanonicalName().c_str() ); return NULL; } // Special case. If the otherClass is an array and the array is // a slice then we need to copy it here. if (PyObject_IsInstance(other, (PyObject*) PyJPArray_Type)) { PyJPArray *array = (PyJPArray*) other; if (array->m_Array->isSlice()) { JPJavaFrame frame = JPJavaFrame::outer(context); jvalue v; v.l = array->m_Array->clone(frame, other); return type->convertToPythonObject(frame, v, true).keep(); } } return type->convertToPythonObject(frame, val->getValue(), true).keep(); Py_RETURN_NONE; JP_PY_CATCH(NULL); } static PyObject *PyJPClass_castEq(PyJPClass *self, PyObject *other) { PyErr_Format(PyExc_TypeError, "Invalid operation"); return NULL; } // Added for auditing static PyObject *PyJPClass_convertToJava(PyJPClass *self, PyObject *other) { JP_PY_TRY("PyJPClass_convertToJava"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); JPClass *cls = self->m_Class; // Test the conversion JPMatch match(&frame, other); cls->findJavaConversion(match); // If there is no conversion report a failure if (match.type == JPMatch::_none) { PyErr_SetString(PyExc_TypeError, "Unable to create an instance."); return 0; } // Otherwise give back a PyJPValue jvalue v = match.convert(); return cls->convertToPythonObject(frame, v, true).keep(); JP_PY_CATCH(NULL); } static PyObject *PyJPClass_repr(PyJPClass *self) { JP_PY_TRY("PyJPClass_repr"); string name = ((PyTypeObject*) self)->tp_name; return PyUnicode_FromFormat("", name.c_str()); JP_PY_CATCH(0); // GCOVR_EXCL_LINE } static PyObject *PyJPClass_getDoc(PyJPClass *self, void *ctxt) { JP_PY_TRY("PyJPMethod_getDoc"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); if (self->m_Doc) { Py_INCREF(self->m_Doc); return self->m_Doc; } // Pack the arguments { JP_TRACE("Pack arguments"); JPPyObject args = JPPyObject::call(PyTuple_Pack(1, self)); JP_TRACE("Call Python"); self->m_Doc = PyObject_Call(_JClassDoc, args.get(), NULL); Py_XINCREF(self->m_Doc); return self->m_Doc; } JP_PY_CATCH(NULL); } int PyJPClass_setDoc(PyJPClass *self, PyObject *obj, void *ctxt) { JP_PY_TRY("PyJPClass_setDoc"); Py_CLEAR(self->m_Doc); self->m_Doc = obj; Py_XINCREF(self->m_Doc); return 0; JP_PY_CATCH(-1); } PyObject* PyJPClass_customize(PyJPClass *self, PyObject *args, PyObject *kwargs) { JP_PY_TRY("PyJPClass_customize"); PyObject *name = NULL; PyObject *value = NULL; if (!PyArg_ParseTuple(args, "OO", &name, &value)) return NULL; if (PyType_Type.tp_setattro((PyObject*) self, name, value) == -1) return NULL; Py_RETURN_NONE; JP_PY_CATCH(NULL); } static PyMethodDef classMethods[] = { {"__instancecheck__", (PyCFunction) PyJPClass_instancecheck, METH_O, ""}, {"__subclasscheck__", (PyCFunction) PyJPClass_subclasscheck, METH_O, ""}, {"mro", (PyCFunction) PyJPClass_mro, METH_NOARGS, ""}, {"_canConvertToJava", (PyCFunction) PyJPClass_canConvertToJava, METH_O, ""}, {"_convertToJava", (PyCFunction) PyJPClass_convertToJava, METH_O, ""}, {"_cast", (PyCFunction) PyJPClass_cast, METH_O, ""}, {"_canCast", (PyCFunction) PyJPClass_canCast, METH_O, ""}, {"__getitem__", (PyCFunction) PyJPClass_array, METH_O | METH_COEXIST, ""}, {"_customize", (PyCFunction) PyJPClass_customize, METH_VARARGS, ""}, {NULL}, }; static PyGetSetDef classGetSets[] = { {"class_", (getter) PyJPClass_class, (setter) PyJPClass_setClass, ""}, {"_hints", (getter) PyJPClass_hints, (setter) PyJPClass_setHints, ""}, {"__doc__", (getter) PyJPClass_getDoc, (setter) PyJPClass_setDoc, NULL, NULL}, {0} }; static PyType_Slot classSlots[] = { { Py_tp_alloc, (void*) PyJPValue_alloc}, { Py_tp_finalize, (void*) PyJPValue_finalize}, { Py_tp_new, (void*) PyJPClass_new}, { Py_tp_init, (void*) PyJPClass_init}, { Py_tp_dealloc, (void*) PyJPClass_dealloc}, { Py_tp_traverse, (void*) PyJPClass_traverse}, { Py_tp_clear, (void*) PyJPClass_clear}, { Py_tp_repr, (void*) PyJPClass_repr}, { Py_tp_getattro, (void*) PyJPClass_getattro}, { Py_tp_setattro, (void*) PyJPClass_setattro}, { Py_tp_methods, (void*) classMethods}, { Py_tp_getset, (void*) classGetSets}, { Py_mp_subscript, (void*) PyJPClass_array}, { Py_nb_matrix_multiply, (void*) PyJPClass_cast}, { Py_nb_inplace_matrix_multiply, (void*) PyJPClass_castEq}, {0} }; PyTypeObject* PyJPClass_Type = NULL; static PyType_Spec classSpec = { "_jpype._JClass", sizeof (PyJPClass), 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, classSlots }; #ifdef __cplusplus } #endif void PyJPClass_initType(PyObject* module) { PyObject *bases = PyTuple_Pack(1, &PyType_Type); PyJPClass_Type = (PyTypeObject*) PyType_FromSpecWithBases(&classSpec, bases); Py_DECREF(bases); JP_PY_CHECK(); PyModule_AddObject(module, "_JClass", (PyObject*) PyJPClass_Type); JP_PY_CHECK(); } JPClass* PyJPClass_getJPClass(PyObject* obj) { try { if (obj == NULL) return NULL; if (PyJPClass_Check(obj)) return ((PyJPClass*) obj)->m_Class; JPValue* javaSlot = PyJPValue_getJavaSlot(obj); if (javaSlot == NULL) return NULL; JPClass *cls = javaSlot->getClass(); if (cls != cls->getContext()->_java_lang_Class) return NULL; JPJavaFrame frame = JPJavaFrame::outer(cls->getContext()); return frame.findClass((jclass) javaSlot->getJavaObject()); } catch (...) // GCOVR_EXCL_LINE { return NULL; // GCOVR_EXCL_LINE } } JPPyObject PyJPClass_getBases(JPJavaFrame &frame, JPClass* cls) { JP_TRACE_IN("PyJPClass_bases"); cls->ensureMembers(frame); // Decide the base for this object JPPyObject baseType; JPContext *context = PyJPModule_getContext(); JPClass *super = cls->getSuperClass(); if (dynamic_cast (cls) == cls) { if (cls == context->_java_lang_Boolean) { baseType = JPPyObject::use((PyObject*) PyJPNumberBool_Type); } else if (cls == context->_java_lang_Character) { baseType = JPPyObject::use((PyObject*) PyJPChar_Type); } else if (cls == context->_java_lang_Boolean || cls == context->_java_lang_Byte || cls == context->_java_lang_Short || cls == context->_java_lang_Integer || cls == context->_java_lang_Long ) { baseType = JPPyObject::use((PyObject*) PyJPNumberLong_Type); } else if (cls == context->_java_lang_Float || cls == context->_java_lang_Double ) { baseType = JPPyObject::use((PyObject*) PyJPNumberFloat_Type); } } else if (JPModifier::isBuffer(cls->getModifiers())) { baseType = JPPyObject::use((PyObject*) PyJPBuffer_Type); } else if (cls == context->_java_lang_Throwable) { baseType = JPPyObject::use((PyObject*) PyJPException_Type); } else if (cls->isArray()) { JPArrayClass* acls = (JPArrayClass*) cls; if (acls->getComponentType()->isPrimitive()) baseType = JPPyObject::use((PyObject*) PyJPArrayPrimitive_Type); else baseType = JPPyObject::use((PyObject*) PyJPArray_Type); } else if (cls->getCanonicalName() == "java.lang.Comparable") { baseType = JPPyObject::use((PyObject*) PyJPComparable_Type); } else if (super == NULL) { baseType = JPPyObject::use((PyObject*) PyJPObject_Type); } const JPClassList& baseItf = cls->getInterfaces(); size_t count = baseItf.size() + (!baseType.isNull() ? 1 : 0) + (super != NULL ? 1 : 0); // Pack into a tuple JPPyObject result = JPPyObject::call(PyList_New(count)); unsigned int i = 0; for (; i < baseItf.size(); i++) { PyList_SetItem(result.get(), i, PyJPClass_create(frame, baseItf[i]).keep()); } if (super != NULL) { PyList_SetItem(result.get(), i++, PyJPClass_create(frame, super).keep()); } if (!baseType.isNull()) { PyList_SetItem(result.get(), i++, baseType.keep()); } return result; JP_TRACE_OUT; } /** * Internal method for wrapping a returned Java class instance. * * This checks the cache for existing wrappers and then * transfers control to JClassFactory. This is required because all of * the post load stuff needs to be in Python. * * @param cls * @return */ JPPyObject PyJPClass_create(JPJavaFrame &frame, JPClass* cls) { JP_TRACE_IN("PyJPClass_create", cls); // Check the cache for speed PyObject *host = (PyObject*) cls->getHost(); if (host == NULL) { frame.newWrapper(cls); host = (PyObject*) cls->getHost(); } return JPPyObject::use(host); JP_TRACE_OUT; } void PyJPClass_hook(JPJavaFrame &frame, JPClass* cls) { JPContext *context = frame.getContext(); PyObject *host = (PyObject*) cls->getHost(); if (host != NULL) return; JPPyObject members = JPPyObject::call(PyDict_New()); JPPyObject args = JPPyObject::call(PyTuple_Pack(3, JPPyString::fromStringUTF8(cls->getCanonicalName()).get(), PyJPClass_getBases(frame, cls).get(), members.get())); // Catch creation loop, the process of creating our parent host = (PyObject*) cls->getHost(); if (host != NULL) return; const JPFieldList & instFields = cls->getFields(); for (JPFieldList::const_iterator iter = instFields.begin(); iter != instFields.end(); iter++) { JPPyObject fieldName(JPPyString::fromStringUTF8((*iter)->getName())); PyDict_SetItem(members.get(), fieldName.get(), PyJPField_create(*iter).get()); } const JPMethodDispatchList& m_Methods = cls->getMethods(); for (JPMethodDispatchList::const_iterator iter = m_Methods.begin(); iter != m_Methods.end(); iter++) { JPPyObject methodName(JPPyString::fromStringUTF8((*iter)->getName())); PyDict_SetItem(members.get(), methodName.get(), PyJPMethod_create(*iter, NULL).get()); } if (cls->isInterface()) { const JPMethodDispatchList& m_Methods = context->_java_lang_Object->getMethods(); for (JPMethodDispatchList::const_iterator iter = m_Methods.begin(); iter != m_Methods.end(); iter++) { JPPyObject methodName(JPPyString::fromStringUTF8((*iter)->getName())); PyDict_SetItem(members.get(), methodName.get(), PyJPMethod_create(*iter, NULL).get()); } } // Call the customizer to make any required changes to the tables. JP_TRACE("call pre"); JPPyObject rc = JPPyObject::call(PyObject_Call(_JClassPre, args.get(), NULL)); JP_TRACE("type new"); // Create the type using the meta class magic JPPyObject vself = JPPyObject::call(PyJPClass_Type->tp_new(PyJPClass_Type, rc.get(), PyJPClassMagic)); PyJPClass *self = (PyJPClass*) vself.get(); // Attach the javaSlot self->m_Class = cls; // self->m_Class->postLoad(); PyJPValue_assignJavaSlot(frame, (PyObject*) self, JPValue(context->_java_lang_Class, (jobject) self->m_Class->getJavaClass())); // Attach the cache (adds reference, thus wrapper lives to end of JVM) JP_TRACE("set host"); cls->setHost((PyObject*) self); // Call the post load routine to attach inner classes JP_TRACE("call post"); args = JPPyObject::call(PyTuple_Pack(1, self)); JPPyObject rc2 = JPPyObject::call(PyObject_Call(_JClassPost, args.get(), NULL)); } jpype-1.3.0/native/python/pyjp_classhints.cpp000066400000000000000000000115371405671516700214150ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "pyjp.h" #ifdef __cplusplus extern "C" { #endif PyObject *PyJPClassHints_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { JP_PY_TRY("PyJPClassHints_new", type); PyJPClassHints *self = (PyJPClassHints*) type->tp_alloc(type, 0); self->m_Hints = new JPClassHints(); return (PyObject*) self; JP_PY_CATCH(NULL); } int PyJPClassHints_init(PyJPClassHints *self, PyObject *args, PyObject *kwargs) { JP_PY_TRY("PyJPClassHints_init", self); return 0; JP_PY_CATCH(-1); } void PyJPClassHints_dealloc(PyJPClassHints *self) { JP_PY_TRY("PyJPClassHints_dealloc", self); delete self->m_Hints; // Free self Py_TYPE(self)->tp_free(self); JP_PY_CATCH(); // GCOVR_EXCL_LINE } PyObject *PyJPClassHints_str(PyJPClassHints *self) { JP_PY_TRY("PyJPClassHints_str", self); return PyUnicode_FromFormat(""); JP_PY_CATCH(NULL); } PyObject *PyJPClassHints_addAttributeConversion(PyJPClassHints *self, PyObject* args, PyObject* kwargs) { JP_PY_TRY("PyJPClassHints_addAttributeConversion", self); char* attribute; PyObject *method; if (!PyArg_ParseTuple(args, "sO", &attribute, &method)) return NULL; JP_TRACE(attribute); JP_TRACE(Py_TYPE(method)->tp_name); if (!PyCallable_Check(method)) { PyErr_SetString(PyExc_TypeError, "callable method is required"); return NULL; } self->m_Hints->addAttributeConversion(string(attribute), method); Py_RETURN_NONE; JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } static void badType(PyObject* t) { PyErr_Format(PyExc_TypeError, "type or protocol is required, not '%s'", Py_TYPE(t)->tp_name); } PyObject *PyJPClassHints_addTypeConversion(PyJPClassHints *self, PyObject* args, PyObject* kwargs) { JP_PY_TRY("PyJPClassHints_addTypeConversion", self); PyObject *type; PyObject *method; unsigned char exact; if (!PyArg_ParseTuple(args, "OOb", &type, &method, &exact)) return NULL; if (!PyType_Check(type) && !PyObject_HasAttrString((PyObject*) type, "__instancecheck__")) { badType(type); return NULL; } if (!PyCallable_Check(method)) { PyErr_SetString(PyExc_TypeError, "callable method is required"); return NULL; } self->m_Hints->addTypeConversion(type, method, exact != 0); Py_RETURN_NONE; JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } PyObject *PyJPClassHints_excludeConversion(PyJPClassHints *self, PyObject* types, PyObject* kwargs) { JP_PY_TRY("PyJPClassHints_excludeConversion", self); if (PyTuple_Check(types)) { Py_ssize_t sz = PyTuple_Size(types); for (Py_ssize_t i = 0; i < sz; ++i) { PyObject *t = PyTuple_GetItem(types, i); if (!PyType_Check(t) && !PyObject_HasAttrString(t, "__instancecheck__")) { badType(t); return NULL; } } for (Py_ssize_t i = 0; i < sz; ++i) { self->m_Hints->excludeConversion(PyTuple_GetItem(types, i)); } } else { if (!PyType_Check(types) && !PyObject_HasAttrString( types, "__instancecheck__")) { badType(types); return NULL; } self->m_Hints->excludeConversion(types); } Py_RETURN_NONE; JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } static PyMethodDef classMethods[] = { {"_addAttributeConversion", (PyCFunction) & PyJPClassHints_addAttributeConversion, METH_VARARGS, ""}, {"_addTypeConversion", (PyCFunction) & PyJPClassHints_addTypeConversion, METH_VARARGS, ""}, {"_excludeConversion", (PyCFunction) & PyJPClassHints_excludeConversion, METH_O, ""}, {NULL}, }; static PyType_Slot hintsSlots[] = { { Py_tp_new , (void*) PyJPClassHints_new}, { Py_tp_init, (void*) PyJPClassHints_init}, { Py_tp_dealloc, (void*) PyJPClassHints_dealloc}, { Py_tp_str, (void*) PyJPClassHints_str}, { Py_tp_doc, (void*) "Java Class Hints"}, { Py_tp_methods, (void*) classMethods}, {0} }; PyTypeObject *PyJPClassHints_Type = NULL; PyType_Spec PyJPClassHintsSpec = { "_jpype._JClassHints", sizeof (PyJPClassHints), 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, hintsSlots }; #ifdef __cplusplus } #endif void PyJPClassHints_initType(PyObject* module) { PyJPClassHints_Type = (PyTypeObject*) PyType_FromSpec(&PyJPClassHintsSpec); JP_PY_CHECK(); // GCOVR_EXCL_LINE sanity check PyModule_AddObject(module, "_JClassHints", (PyObject*) PyJPClassHints_Type); JP_PY_CHECK(); // GCOVR_EXCL_LINE sanity check } jpype-1.3.0/native/python/pyjp_field.cpp000066400000000000000000000074261405671516700203270ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "pyjp.h" #include "jp_field.h" #ifdef __cplusplus extern "C" { #endif struct PyJPField { PyObject_HEAD JPField* m_Field; } ; static void PyJPField_dealloc(PyJPField *self) { self->m_Field = NULL; Py_TYPE(self)->tp_free(self); } static PyObject *PyJPField_get(PyJPField *self, PyObject *obj, PyObject *type) { JP_PY_TRY("PyJPField_get"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); // Clear any pending interrupts if we are on the main thread. if (hasInterrupt()) frame.clearInterrupt(false); if (self->m_Field->isStatic()) return self->m_Field->getStaticField().keep(); if (obj == NULL) JP_RAISE(PyExc_AttributeError, "Field is not static"); JPValue *jval = PyJPValue_getJavaSlot(obj); if (jval == NULL) JP_RAISE(PyExc_AttributeError, "Field requires instance value"); return self->m_Field->getField(jval->getValue().l).keep(); JP_PY_CATCH(NULL); } static int PyJPField_set(PyJPField *self, PyObject *obj, PyObject *pyvalue) { JP_PY_TRY("PyJPField_set"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); if (self->m_Field->isFinal()) { PyErr_SetString(PyExc_AttributeError, "Field is final"); return -1; } if (self->m_Field->isStatic()) { self->m_Field->setStaticField(pyvalue); return 0; } if (obj == Py_None || PyJPClass_Check(obj)) { PyErr_SetString(PyExc_AttributeError, "Field is not static"); return -1; } JPValue *jval = PyJPValue_getJavaSlot(obj); if (jval == NULL) { PyErr_Format(PyExc_AttributeError, "Field requires instance value, not '%s'", Py_TYPE(obj)->tp_name); return -1; } self->m_Field->setField(jval->getValue().l, pyvalue); return 0; JP_PY_CATCH(-1); } static PyObject *PyJPField_repr(PyJPField *self) { JP_PY_TRY("PyJPField_repr"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); return PyUnicode_FromFormat("", self->m_Field->getName().c_str(), self->m_Field->getClass()->getCanonicalName().c_str() ); JP_PY_CATCH(NULL); } static PyGetSetDef fieldGetSets[] = { {0} }; static PyType_Slot fieldSlots[] = { { Py_tp_dealloc, (void*) PyJPField_dealloc}, { Py_tp_descr_get, (void*) PyJPField_get}, { Py_tp_descr_set, (void*) PyJPField_set}, { Py_tp_repr, (void*) &PyJPField_repr}, { Py_tp_getset, (void*) &fieldGetSets}, {0} }; PyTypeObject *PyJPField_Type = NULL; PyType_Spec PyJPFieldSpec = { "_jpype._JField", sizeof (PyJPField), 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, fieldSlots }; #ifdef __cplusplus } #endif void PyJPField_initType(PyObject* module) { PyJPField_Type = (PyTypeObject*) PyType_FromSpec(&PyJPFieldSpec); JP_PY_CHECK(); PyModule_AddObject(module, "_JField", (PyObject*) PyJPField_Type); JP_PY_CHECK(); } JPPyObject PyJPField_create(JPField* m) { JP_TRACE_IN("PyJPField_create"); PyJPField* self = (PyJPField*) PyJPField_Type->tp_alloc(PyJPField_Type, 0); JP_PY_CHECK(); self->m_Field = m; return JPPyObject::claim((PyObject*) self); JP_TRACE_OUT; // GCOVR_EXCL_LINE } jpype-1.3.0/native/python/pyjp_method.cpp000066400000000000000000000310171405671516700205150ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "pyjp.h" #include "jp_methoddispatch.h" #include "jp_method.h" #ifdef __cplusplus extern "C" { #endif struct PyJPMethod { PyFunctionObject func; JPMethodDispatch* m_Method; PyObject* m_Instance; PyObject* m_Doc; PyObject* m_Annotations; PyObject* m_CodeRep; } ; static int PyJPMethod_traverse(PyJPMethod *self, visitproc visit, void *arg) { Py_VISIT(self->m_Instance); Py_VISIT(self->m_Doc); Py_VISIT(self->m_Annotations); Py_VISIT(self->m_CodeRep); return 0; } static int PyJPMethod_clear(PyJPMethod *self) { Py_CLEAR(self->m_Instance); Py_CLEAR(self->m_Doc); Py_CLEAR(self->m_Annotations); Py_CLEAR(self->m_CodeRep); return 0; } static void PyJPMethod_dealloc(PyJPMethod *self) { JP_PY_TRY("PyJPMethod_dealloc"); PyObject_GC_UnTrack(self); Py_TRASHCAN_BEGIN(self, PyJPMethod_dealloc) PyJPMethod_clear(self); Py_TYPE(self)->tp_free(self); Py_TRASHCAN_END JP_PY_CATCH_NONE(); // GCOVR_EXCL_LINE } static PyObject *PyJPMethod_get(PyJPMethod *self, PyObject *obj, PyObject *type) { JP_PY_TRY("PyJPMethod_get"); PyJPModule_getContext(); if (obj == NULL) { Py_INCREF((PyObject*) self); JP_TRACE_PY("method get (inc)", (PyObject*) self); return (PyObject*) self; } PyJPMethod *out = (PyJPMethod*) PyJPMethod_create(self->m_Method, obj).keep(); if (self->m_Doc != NULL) { out->m_Doc = self->m_Doc; Py_INCREF(out->m_Doc); } if (self->m_Annotations != NULL) { out->m_Annotations = self->m_Annotations; Py_INCREF(out->m_Annotations); } return (PyObject*) out; JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } static PyObject *PyJPMethod_call(PyJPMethod *self, PyObject *args, PyObject *kwargs) { JP_PY_TRY("PyJPMethod_call"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); JP_TRACE(self->m_Method->getName()); // Clear any pending interrupts if we are on the main thread if (hasInterrupt()) frame.clearInterrupt(false); PyObject *out = NULL; if (self->m_Instance == NULL) { JPPyObjectVector vargs(args); out = self->m_Method->invoke(frame, vargs, false).keep(); } else { JPPyObjectVector vargs(self->m_Instance, args); out = self->m_Method->invoke(frame, vargs, true).keep(); } return out; JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } static PyObject *PyJPMethod_matches(PyJPMethod *self, PyObject *args, PyObject *kwargs) { JP_PY_TRY("PyJPMethod_matches"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); JP_TRACE(self->m_Method->getName()); if (self->m_Instance == NULL) { JPPyObjectVector vargs(args); return PyBool_FromLong(self->m_Method->matches(frame, vargs, false)); } else { JPPyObjectVector vargs(self->m_Instance, args); return PyBool_FromLong(self->m_Method->matches(frame, vargs, true)); } JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } static PyObject *PyJPMethod_str(PyJPMethod *self) { JP_PY_TRY("PyJPMethod_str"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); return PyUnicode_FromFormat("%s.%s", self->m_Method->getClass()->getCanonicalName().c_str(), self->m_Method->getName().c_str()); JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } static PyObject *PyJPMethod_repr(PyJPMethod *self) { JP_PY_TRY("PyJPMethod_repr"); PyJPModule_getContext(); return PyUnicode_FromFormat("", (self->m_Instance != NULL) ? "bound " : "", self->m_Method->getName().c_str(), self->m_Method->getClass()->getCanonicalName().c_str()); JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } static PyObject *PyJPMethod_getSelf(PyJPMethod *self, void *ctxt) { JP_PY_TRY("PyJPMethod_getSelf"); PyJPModule_getContext(); if (self->m_Instance == NULL) Py_RETURN_NONE; Py_INCREF(self->m_Instance); return self->m_Instance; JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } static PyObject *PyJPMethod_getNone(PyJPMethod *self, void *ctxt) { Py_RETURN_NONE; } static PyObject *PyJPMethod_getName(PyJPMethod *self, void *ctxt) { JP_PY_TRY("PyJPMethod_getName"); PyJPModule_getContext(); return JPPyString::fromStringUTF8(self->m_Method->getName()).keep(); JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } static PyObject *PyJPMethod_getQualName(PyJPMethod *self, void *ctxt) { JP_PY_TRY("PyJPMethod_getQualName"); PyJPModule_getContext(); return PyUnicode_FromFormat("%s.%s", self->m_Method->getClass()->getCanonicalName().c_str(), self->m_Method->getName().c_str()); JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } static PyObject *PyJPMethod_getDoc(PyJPMethod *self, void *ctxt) { JP_PY_TRY("PyJPMethod_getDoc"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); if (self->m_Doc) { Py_INCREF(self->m_Doc); return self->m_Doc; } // Convert the overloads JP_TRACE("Convert overloads"); const JPMethodList& overloads = self->m_Method->getMethodOverloads(); JPPyObject ov = JPPyObject::call(PyTuple_New(overloads.size())); int i = 0; JPClass* methodClass = frame.findClassByName("java.lang.reflect.Method"); for (JPMethodList::const_iterator iter = overloads.begin(); iter != overloads.end(); ++iter) { JP_TRACE("Set overload", i); jvalue v; v.l = (*iter)->getJava(); JPPyObject obj(methodClass->convertToPythonObject(frame, v, true)); PyTuple_SetItem(ov.get(), i++, obj.keep()); } // Pack the arguments { JP_TRACE("Pack arguments"); jvalue v; v.l = (jobject) self->m_Method->getClass()->getJavaClass(); JPPyObject obj(context->_java_lang_Class->convertToPythonObject(frame, v, true)); JPPyObject args = JPPyObject::call(PyTuple_Pack(3, self, obj.get(), ov.get())); JP_TRACE("Call Python"); self->m_Doc = PyObject_Call(_JMethodDoc, args.get(), NULL); Py_XINCREF(self->m_Doc); return self->m_Doc; } JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } int PyJPMethod_setDoc(PyJPMethod *self, PyObject *obj, void *ctxt) { JP_PY_TRY("PyJPMethod_setDoc"); Py_CLEAR(self->m_Doc); self->m_Doc = obj; Py_XINCREF(self->m_Doc); return 0; JP_PY_CATCH(-1); // GCOVR_EXCL_LINE } PyObject *PyJPMethod_getAnnotations(PyJPMethod *self, void *ctxt) { JP_PY_TRY("PyJPMethod_getAnnotations"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); if (self->m_Annotations) { Py_INCREF(self->m_Annotations); return self->m_Annotations; } // Convert the overloads JP_TRACE("Convert overloads"); const JPMethodList& overloads = self->m_Method->getMethodOverloads(); JPPyObject ov = JPPyObject::call(PyTuple_New(overloads.size())); int i = 0; JPClass* methodClass = frame.findClassByName("java.lang.reflect.Method"); for (JPMethodList::const_iterator iter = overloads.begin(); iter != overloads.end(); ++iter) { JP_TRACE("Set overload", i); jvalue v; v.l = (*iter)->getJava(); JPPyObject obj(methodClass->convertToPythonObject(frame, v, true)); PyTuple_SetItem(ov.get(), i++, obj.keep()); } // Pack the arguments { JP_TRACE("Pack arguments"); jvalue v; v.l = (jobject) self->m_Method->getClass()->getJavaClass(); JPPyObject obj(context->_java_lang_Class->convertToPythonObject(frame, v, true)); JPPyObject args = JPPyObject::call(PyTuple_Pack(3, self, obj.get(), ov.get())); JP_TRACE("Call Python"); self->m_Annotations = PyObject_Call(_JMethodAnnotations, args.get(), NULL); } Py_XINCREF(self->m_Annotations); return self->m_Annotations; JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } int PyJPMethod_setAnnotations(PyJPMethod *self, PyObject* obj, void *ctx) { Py_CLEAR(self->m_Annotations); self->m_Annotations = obj; Py_XINCREF(self->m_Annotations); return 0; } PyObject *PyJPMethod_getCodeAttr(PyJPMethod *self, void *ctx, const char *attr) { JP_PY_TRY("PyJPMethod_getCodeAttr"); PyJPModule_getContext(); if (self->m_CodeRep == NULL) { JPPyObject args = JPPyObject::call(PyTuple_Pack(1, self)); JP_TRACE("Call Python"); self->m_CodeRep = PyObject_Call(_JMethodCode, args.get(), NULL); } return PyObject_GetAttrString(self->m_CodeRep, attr); JP_PY_CATCH(NULL); } PyObject *PyJPMethod_getCode(PyJPMethod *self, void *ctxt) { return PyJPMethod_getCodeAttr(self, ctxt, "__code__"); } PyObject *PyJPMethod_getClosure(PyJPMethod *self, void *ctxt) { return PyJPMethod_getCodeAttr(self, ctxt, "__closure__"); } PyObject *PyJPMethod_getGlobals(PyJPMethod *self, void *ctxt) { return PyJPMethod_getCodeAttr(self, ctxt, "__globals__"); } PyObject *PyJPMethod_isBeanAccessor(PyJPMethod *self, PyObject *arg) { JP_PY_TRY("PyJPMethod_isBeanAccessor"); PyJPModule_getContext(); return PyBool_FromLong(self->m_Method->isBeanAccessor()); JP_PY_CATCH(NULL); } PyObject *PyJPMethod_isBeanMutator(PyJPMethod *self, PyObject *arg) { JP_PY_TRY("PyJPMethod_isBeanMutator"); PyJPModule_getContext(); return PyBool_FromLong(self->m_Method->isBeanMutator()); JP_PY_CATCH(NULL); } PyObject *PyJPMethod_matchReport(PyJPMethod *self, PyObject *args) { JP_PY_TRY("PyJPMethod_matchReport"); PyJPModule_getContext(); JPPyObjectVector vargs(args); string report = self->m_Method->matchReport(vargs); return JPPyString::fromStringUTF8(report).keep(); JP_PY_CATCH(NULL); } static PyMethodDef methodMethods[] = { {"_isBeanAccessor", (PyCFunction) (&PyJPMethod_isBeanAccessor), METH_NOARGS, ""}, {"_isBeanMutator", (PyCFunction) (&PyJPMethod_isBeanMutator), METH_NOARGS, ""}, {"matchReport", (PyCFunction) (&PyJPMethod_matchReport), METH_VARARGS, ""}, // This is currently private but may be promoted {"_matches", (PyCFunction) (&PyJPMethod_matches), METH_VARARGS, ""}, {NULL}, }; struct PyGetSetDef methodGetSet[] = { {"__self__", (getter) (&PyJPMethod_getSelf), NULL, NULL, NULL}, {"__name__", (getter) (&PyJPMethod_getName), NULL, NULL, NULL}, {"__doc__", (getter) (&PyJPMethod_getDoc), (setter) (&PyJPMethod_setDoc), NULL, NULL}, {"__annotations__", (getter) (&PyJPMethod_getAnnotations), (setter) (&PyJPMethod_setAnnotations), NULL, NULL}, {"__closure__", (getter) (&PyJPMethod_getClosure), NULL, NULL, NULL}, {"__code__", (getter) (&PyJPMethod_getCode), NULL, NULL, NULL}, {"__defaults__", (getter) (&PyJPMethod_getNone), NULL, NULL, NULL}, {"__kwdefaults__", (getter) (&PyJPMethod_getNone), NULL, NULL, NULL}, {"__globals__", (getter) (&PyJPMethod_getGlobals), NULL, NULL, NULL}, {"__qualname__", (getter) (&PyJPMethod_getQualName), NULL, NULL, NULL}, {NULL}, }; static PyType_Slot methodSlots[] = { {Py_tp_dealloc, (void*) PyJPMethod_dealloc}, {Py_tp_traverse, (void*) PyJPMethod_traverse}, {Py_tp_clear, (void*) PyJPMethod_clear}, {Py_tp_repr, (void*) PyJPMethod_repr}, {Py_tp_call, (void*) PyJPMethod_call}, {Py_tp_str, (void*) PyJPMethod_str}, {Py_tp_descr_get, (void*) PyJPMethod_get}, {Py_tp_methods, (void*) methodMethods}, {Py_tp_getset, (void*) methodGetSet}, {0} }; PyTypeObject *PyJPMethod_Type = NULL; static PyType_Spec methodSpec = { "_jpype._JMethod", sizeof (PyJPMethod), 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, methodSlots }; #ifdef __cplusplus } #endif void PyJPMethod_initType(PyObject* module) { // We inherit from PyFunction_Type just so we are an instance // for purposes of inspect and tab completion tools. But // we will just ignore their memory layout as we have our own. JPPyObject tuple = JPPyObject::call(PyTuple_Pack(1, &PyFunction_Type)); unsigned long flags = PyFunction_Type.tp_flags; PyFunction_Type.tp_flags |= Py_TPFLAGS_BASETYPE; PyJPMethod_Type = (PyTypeObject*) PyType_FromSpecWithBases(&methodSpec, tuple.get()); PyFunction_Type.tp_flags = flags; JP_PY_CHECK(); PyModule_AddObject(module, "_JMethod", (PyObject*) PyJPMethod_Type); JP_PY_CHECK(); } JPPyObject PyJPMethod_create(JPMethodDispatch *m, PyObject *instance) { JP_TRACE_IN("PyJPMethod_create"); PyJPMethod* self = (PyJPMethod*) PyJPMethod_Type->tp_alloc(PyJPMethod_Type, 0); JP_PY_CHECK(); self->m_Method = m; self->m_Instance = instance; self->m_Doc = NULL; self->m_Annotations = NULL; self->m_CodeRep = NULL; Py_XINCREF(self->m_Instance); return JPPyObject::claim((PyObject*) self); JP_TRACE_OUT; /// GCOVR_EXCL_LINE } jpype-1.3.0/native/python/pyjp_module.cpp000066400000000000000000000611571405671516700205320ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "pyjp.h" #include "jp_arrayclass.h" #include "jp_primitive_accessor.h" #include "jp_gc.h" #include "jp_stringtype.h" #include "jp_classloader.h" void PyJPModule_installGC(PyObject* module); bool _jp_cpp_exceptions = false; extern void PyJPArray_initType(PyObject* module); extern void PyJPBuffer_initType(PyObject* module); extern void PyJPClass_initType(PyObject* module); extern void PyJPField_initType(PyObject* module); extern void PyJPMethod_initType(PyObject* module); extern void PyJPMonitor_initType(PyObject* module); extern void PyJPProxy_initType(PyObject* module); extern void PyJPObject_initType(PyObject* module); extern void PyJPNumber_initType(PyObject* module); extern void PyJPClassHints_initType(PyObject* module); extern void PyJPPackage_initType(PyObject* module); extern void PyJPChar_initType(PyObject* module); static PyObject *PyJPModule_convertBuffer(JPPyBuffer& buffer, PyObject *dtype); // To ensure no leaks (requires C++ linkage) class JPViewWrapper { public: JPViewWrapper() { view = new Py_buffer(); } ~JPViewWrapper() { delete view; } Py_buffer *view; } ; PyObject* _JArray = NULL; PyObject* _JChar = NULL; PyObject* _JObject = NULL; PyObject* _JInterface = NULL; PyObject* _JException = NULL; PyObject* _JClassPre = NULL; PyObject* _JClassPost = NULL; PyObject* _JClassDoc = NULL; PyObject* _JMethodDoc = NULL; PyObject* _JMethodAnnotations = NULL; PyObject* _JMethodCode = NULL; PyObject* _JObjectKey = NULL; PyObject* _JVMNotRunning = NULL; void PyJPModule_loadResources(PyObject* module) { // Note that if any resource is missing the user will get // the message: // // AttributeError: module '_jpype' has no attribute 'SomeResource' // The above exception was the direct cause of the following exception: // // Traceback (most recent call last): // File ... // RuntimeError: JPype resource is missing try { // Complete the initialization here _JObject = PyObject_GetAttrString(module, "JObject"); JP_PY_CHECK(); Py_INCREF(_JObject); _JInterface = PyObject_GetAttrString(module, "JInterface"); JP_PY_CHECK(); Py_INCREF(_JInterface); _JArray = PyObject_GetAttrString(module, "JArray"); JP_PY_CHECK(); Py_INCREF(_JArray); _JChar = PyObject_GetAttrString(module, "JChar"); JP_PY_CHECK(); Py_INCREF(_JChar); _JException = PyObject_GetAttrString(module, "JException"); JP_PY_CHECK(); Py_INCREF(_JException); _JClassPre = PyObject_GetAttrString(module, "_jclassPre"); JP_PY_CHECK(); Py_INCREF(_JClassPre); _JClassPost = PyObject_GetAttrString(module, "_jclassPost"); JP_PY_CHECK(); Py_INCREF(_JClassPost); JP_PY_CHECK(); _JClassDoc = PyObject_GetAttrString(module, "_jclassDoc"); JP_PY_CHECK(); Py_INCREF(_JClassDoc); _JMethodDoc = PyObject_GetAttrString(module, "getMethodDoc"); Py_INCREF(_JMethodDoc); _JMethodAnnotations = PyObject_GetAttrString(module, "getMethodAnnotations"); JP_PY_CHECK(); Py_INCREF(_JMethodAnnotations); _JMethodCode = PyObject_GetAttrString(module, "getMethodCode"); JP_PY_CHECK(); Py_INCREF(_JMethodCode); _JObjectKey = PyCapsule_New(module, "constructor key", NULL); } catch (JPypeException&) // GCOVR_EXCL_LINE { // GCOVR_EXCL_START PyJP_SetStringWithCause(PyExc_RuntimeError, "JPype resource is missing"); JP_RAISE_PYTHON(); // GCOVR_EXCL_STOP } } #ifdef __cplusplus extern "C" { #endif // GCOVR_EXCL_START // This is used exclusively during startup void PyJP_SetStringWithCause(PyObject *exception, const char *str) { // See _PyErr_TrySetFromCause PyObject *exc1, *val1, *tb1; PyErr_Fetch(&exc1, &val1, &tb1); PyErr_NormalizeException(&exc1, &val1, &tb1); if (tb1 != NULL) { PyException_SetTraceback(val1, tb1); Py_DECREF(tb1); } Py_DECREF(exc1); PyErr_SetString(exception, str); PyObject *exc2, *val2, *tb2; PyErr_Fetch(&exc2, &val2, &tb2); PyErr_NormalizeException(&exc2, &val2, &tb2); PyException_SetCause(val2, val1); PyErr_Restore(exc2, val2, tb2); } // GCOVR_EXCL_STOP PyObject* PyJP_GetAttrDescriptor(PyTypeObject *type, PyObject *attr_name) { JP_PY_TRY("Py_GetAttrDescriptor"); if (type->tp_mro == NULL) return NULL; // GCOVR_EXCL_LINE PyObject *mro = type->tp_mro; Py_ssize_t n = PyTuple_Size(mro); for (Py_ssize_t i = 0; i < n; ++i) { PyTypeObject *type2 = (PyTypeObject*) PyTuple_GetItem(mro, i); PyObject *res = PyDict_GetItem(type2->tp_dict, attr_name); if (res) { Py_INCREF(res); return res; } } // Last check is id in the parent { PyObject *res = PyDict_GetItem(Py_TYPE(type)->tp_dict, attr_name); if (res) { Py_INCREF(res); return res; } } return NULL; JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } int PyJP_IsSubClassSingle(PyTypeObject* type, PyTypeObject* obj) { if (type == NULL || obj == NULL) return 0; // GCOVR_EXCL_LINE PyObject* mro1 = obj->tp_mro; Py_ssize_t n1 = PyTuple_Size(mro1); Py_ssize_t n2 = PyTuple_Size(type->tp_mro); if (n1 < n2) return 0; return PyTuple_GetItem(mro1, n1 - n2) == (PyObject*) type; } int PyJP_IsInstanceSingle(PyObject* obj, PyTypeObject* type) { if (type == NULL || obj == NULL) return 0; // GCOVR_EXCL_LINE return PyJP_IsSubClassSingle(type, Py_TYPE(obj)); } #ifndef ANDROID extern JNIEnv *Android_JNI_GetEnv(); static PyObject* PyJPModule_startup(PyObject* module, PyObject* pyargs) { JP_PY_TRY("PyJPModule_startup"); PyObject* vmOpt; PyObject* vmPath; char ignoreUnrecognized = true; char convertStrings = false; char interrupt = false; if (!PyArg_ParseTuple(pyargs, "OO!bbb", &vmPath, &PyTuple_Type, &vmOpt, &ignoreUnrecognized, &convertStrings, &interrupt)) return NULL; if (!(JPPyString::check(vmPath))) { PyErr_SetString(PyExc_TypeError, "Java JVM path must be a string"); return NULL; } string cVmPath = JPPyString::asStringUTF8(vmPath); JP_TRACE("vmpath", cVmPath); StringVector args; JPPySequence seq = JPPySequence::use(vmOpt); for (int i = 0; i < seq.size(); i++) { JPPyObject obj(seq[i]); if (JPPyString::check(obj.get())) { // TODO support unicode string v = JPPyString::asStringUTF8(obj.get()); JP_TRACE("arg", v); args.push_back(v); } else { PyErr_SetString(PyExc_TypeError, "VM Arguments must be strings"); return NULL; } } // This section was moved down to make it easier to cover error cases if (JPContext_global->isRunning()) { PyErr_SetString(PyExc_OSError, "JVM is already started"); return NULL; } // install the gc hook PyJPModule_installGC(module); PyJPModule_loadResources(module); JPContext_global->startJVM(cVmPath, args, ignoreUnrecognized != 0, convertStrings != 0, interrupt != 0); Py_RETURN_NONE; JP_PY_CATCH(NULL); } static PyObject* PyJPModule_shutdown(PyObject* obj, PyObject* pyargs, PyObject* kwargs) { JP_PY_TRY("PyJPModule_shutdown"); char destroyJVM = true; char freeJVM = true; if (!PyArg_ParseTuple(pyargs, "bb", &destroyJVM, &freeJVM)) return NULL; JPContext_global->shutdownJVM(destroyJVM, freeJVM); Py_RETURN_NONE; JP_PY_CATCH(NULL); } #endif static PyObject* PyJPModule_isStarted(PyObject* obj) { return PyBool_FromLong(JPContext_global->isRunning()); } #ifndef ANDROID static PyObject* PyJPModule_attachThread(PyObject* obj) { JP_PY_TRY("PyJPModule_attachThread"); PyJPModule_getContext()->attachCurrentThread(); Py_RETURN_NONE; JP_PY_CATCH(NULL); } static PyObject* PyJPModule_attachThreadAsDaemon(PyObject* obj) { JP_PY_TRY("PyJPModule_attachThreadAsDaemon"); PyJPModule_getContext()->attachCurrentThreadAsDaemon(); Py_RETURN_NONE; JP_PY_CATCH(NULL); } static PyObject* PyJPModule_detachThread(PyObject* obj) { JP_PY_TRY("PyJPModule_detachThread"); if (JPContext_global->isRunning()) JPContext_global->detachCurrentThread(); Py_RETURN_NONE; JP_PY_CATCH(NULL); } #endif static PyObject* PyJPModule_isThreadAttached(PyObject* obj) { JP_PY_TRY("PyJPModule_isThreadAttached"); if (!JPContext_global->isRunning()) return PyBool_FromLong(0); // GCOVR_EXCL_LINE return PyBool_FromLong(JPContext_global->isThreadAttached()); JP_PY_CATCH(NULL); } // Cleanup hook for Py_buffer static void releaseView(void* view) { if (view != 0) { PyBuffer_Release((Py_buffer*) view); delete (Py_buffer*) view; } } static PyObject* PyJPModule_convertToDirectByteBuffer(PyObject* self, PyObject* src) { JP_PY_TRY("PyJPModule_convertToDirectByteBuffer"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); if (PyObject_CheckBuffer(src)) { JPViewWrapper vw; if (PyObject_GetBuffer(src, vw.view, PyBUF_WRITABLE) == -1) return NULL; // Create a byte buffer jvalue v; v.l = frame.NewDirectByteBuffer(vw.view->buf, vw.view->len); // Bind lifespan of the view to the java object. frame.registerRef(v.l, vw.view, &releaseView); vw.view = 0; JPClass *type = frame.findClassForObject(v.l); return type->convertToPythonObject(frame, v, false).keep(); } PyErr_SetString(PyExc_TypeError, "convertToDirectByteBuffer requires buffer support"); JP_PY_CATCH(NULL); } static PyObject* PyJPModule_enableStacktraces(PyObject* self, PyObject* src) { _jp_cpp_exceptions = PyObject_IsTrue(src); Py_RETURN_TRUE; } PyObject *PyJPModule_newArrayType(PyObject *module, PyObject *args) { JP_PY_TRY("PyJPModule_newArrayType"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); PyObject *type, *dims; if (!PyArg_ParseTuple(args, "OO", &type, &dims)) return NULL; if (!PyIndex_Check(dims)) { PyErr_SetString(PyExc_TypeError, "dims must be an integer"); return NULL; } long d = PyLong_AsLong(dims); JPClass* cls = PyJPClass_getJPClass(type); if (cls == NULL) { PyErr_SetString(PyExc_TypeError, "Java class required"); return NULL; } JPClass* arraycls = cls->newArrayType(frame, d); return PyJPClass_create(frame, arraycls).keep(); JP_PY_CATCH(NULL); } PyObject *PyJPModule_getClass(PyObject* module, PyObject *obj) { JP_PY_TRY("PyJPModule_getClass"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); JPClass* cls; if (JPPyString::check(obj)) { // String From Python cls = frame.findClassByName(JPPyString::asStringUTF8(obj)); if (cls == NULL) { PyErr_SetString(PyExc_ValueError, "Unable to find Java class"); return NULL; } } else { // From an existing java.lang.Class object JPValue *value = PyJPValue_getJavaSlot(obj); if (value == 0 || value->getClass() != context->_java_lang_Class) { PyErr_Format(PyExc_TypeError, "JClass requires str or java.lang.Class instance, not '%s'", Py_TYPE(obj)->tp_name); return NULL; } cls = frame.findClass((jclass) value->getValue().l); if (cls == NULL) { PyErr_SetString(PyExc_ValueError, "Unable to find class"); return NULL; } } return PyJPClass_create(frame, cls).keep(); JP_PY_CATCH(NULL); } PyObject *PyJPModule_hasClass(PyObject* module, PyObject *obj) { JP_PY_TRY("PyJPModule_hasClass"); if (!JPContext_global->isRunning()) Py_RETURN_FALSE; // GCOVR_EXCL_LINE JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); JPClass* cls; if (JPPyString::check(obj)) { // String From Python cls = frame.findClassByName(JPPyString::asStringUTF8(obj)); if (cls == NULL) { PyErr_SetString(PyExc_ValueError, "Unable to find Java class"); return NULL; } } else { PyErr_Format(PyExc_TypeError, "str is required, not '%s'", Py_TYPE(obj)->tp_name); return NULL; } PyObject *host = (PyObject*) cls->getHost(); return PyBool_FromLong(host != NULL); JP_PY_CATCH(NULL); } static PyObject *PyJPModule_arrayFromBuffer(PyObject *module, PyObject *args, PyObject *kwargs) { JP_PY_TRY("PyJPModule_arrayFromBuffer"); PyObject *source = 0; PyObject *dtype = 0; if (!PyArg_ParseTuple(args, "OO", &source, &dtype)) return NULL; if (!PyObject_CheckBuffer(source)) { PyErr_Format(PyExc_TypeError, "'%s' does not support buffers", Py_TYPE(source)->tp_name); return NULL; } // NUMPy does a series of probes looking for the best supported format, // we will do the same. { JPPyBuffer buffer(source, PyBUF_FULL_RO); if (buffer.valid()) return PyJPModule_convertBuffer(buffer, dtype); } { JPPyBuffer buffer(source, PyBUF_RECORDS_RO); if (buffer.valid()) return PyJPModule_convertBuffer(buffer, dtype); } { JPPyBuffer buffer(source, PyBUF_ND | PyBUF_FORMAT); if (buffer.valid()) return PyJPModule_convertBuffer(buffer, dtype); } PyErr_Format(PyExc_TypeError, "buffer protocol for '%s' not supported", Py_TYPE(source)->tp_name); return NULL; JP_PY_CATCH(NULL); } PyObject *PyJPModule_collect(PyObject* module, PyObject *obj) { JPContext* context = JPContext_global; if (!context->isRunning()) Py_RETURN_NONE; PyObject *a1 = PyTuple_GetItem(obj, 0); if (!PyUnicode_Check(a1)) { PyErr_SetString(PyExc_TypeError, "Bad callback argument"); return NULL; } if (PyUnicode_ReadChar(a1, 2) == 'a') { context->m_GC->onStart(); } else { context->m_GC->onEnd(); } Py_RETURN_NONE; } // GCOVR_EXCL_START PyObject *PyJPModule_gcStats(PyObject* module, PyObject *obj) { JPContext *context = PyJPModule_getContext(); JPGCStats stats; context->m_GC->getStats(stats); PyObject *out = PyDict_New(); PyObject *res; PyDict_SetItemString(out, "current", res = PyLong_FromSsize_t(stats.current_rss)); Py_DECREF(res); PyDict_SetItemString(out, "java", res = PyLong_FromSsize_t(stats.java_rss)); Py_DECREF(res); PyDict_SetItemString(out, "python", res = PyLong_FromSsize_t(stats.python_rss)); Py_DECREF(res); PyDict_SetItemString(out, "max", res = PyLong_FromSsize_t(stats.max_rss)); Py_DECREF(res); PyDict_SetItemString(out, "min", res = PyLong_FromSsize_t(stats.min_rss)); Py_DECREF(res); PyDict_SetItemString(out, "triggered", res = PyLong_FromSsize_t(stats.python_triggered)); Py_DECREF(res); return out; } // GCOVR_EXCL_STOP static PyObject* PyJPModule_isPackage(PyObject *module, PyObject *pkg) { JP_PY_TRY("PyJPModule_isPackage"); if (!PyUnicode_Check(pkg)) { PyErr_Format(PyExc_TypeError, "isPackage required unicode"); return NULL; } JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); return PyBool_FromLong(frame.isPackage(JPPyString::asStringUTF8(pkg))); JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } #if 1 // GCOVR_EXCL_START // This code was used in testing the Java slot memory layout. It serves no purpose outside of debugging that issue. PyObject* examine(PyObject *module, PyObject *other) { JP_PY_TRY("examine"); int ret = 0; PyTypeObject *type; if (PyType_Check(other)) type = (PyTypeObject*) other; else type = Py_TYPE(other); printf("======\n"); int offset = 0; if (!PyType_Check(other)) { offset = PyJPValue_getJavaSlotOffset(other); printf(" Object:\n"); printf(" size: %d\n", (int) Py_SIZE(other)); printf(" dictoffset: %d\n", (int) ((long long) _PyObject_GetDictPtr(other)-(long long) other)); printf(" javaoffset: %d\n", offset); } printf(" Type: %p\n", type); printf(" name: %s\n", type->tp_name); printf(" typename: %s\n", Py_TYPE(type)->tp_name); printf(" gc: %d\n", (type->tp_flags & Py_TPFLAGS_HAVE_GC) == Py_TPFLAGS_HAVE_GC); printf(" basicsize: %d\n", (int) type->tp_basicsize); printf(" itemsize: %d\n", (int) type->tp_itemsize); printf(" dictoffset: %d\n", (int) type->tp_dictoffset); printf(" weaklistoffset: %d\n", (int) type->tp_weaklistoffset); printf(" hasJavaSlot: %d\n", PyJPValue_hasJavaSlot(type)); printf(" getattro: %p\n", type->tp_getattro); printf(" setattro: %p\n", type->tp_setattro); printf(" getattr: %p\n", type->tp_getattr); printf(" setattr: %p\n", type->tp_setattr); printf(" alloc: %p\n", type->tp_alloc); printf(" free: %p\n", type->tp_free); printf(" finalize: %p\n", type->tp_finalize); long v = _PyObject_VAR_SIZE(type, 1)+(PyJPValue_hasJavaSlot(type)?sizeof (JPValue):0); printf(" size?: %ld\n",v); printf("======\n"); return PyBool_FromLong(ret); JP_PY_CATCH(NULL); } // GCOVR_EXCL_STOP #endif // GCOVR_EXCL_START int _PyJPModule_trace = 0; static PyObject* PyJPModule_trace(PyObject *module, PyObject *args) { bool old = _PyJPModule_trace; _PyJPModule_trace = PyLong_AsLong(args); return PyLong_FromLong(old); } // GCOVR_EXCL_STOP #ifdef JP_INSTRUMENTATION uint32_t _PyJPModule_fault_code = -1; static PyObject* PyJPModule_fault(PyObject *module, PyObject *args) { if (args == Py_None) { _PyJPModule_fault_code = 0; Py_RETURN_NONE; } string code = JPPyString::asStringUTF8(args); uint32_t u = 0; for (size_t i = 0; i < code.size(); ++i) u = u * 0x1a481023 + code[i]; _PyJPModule_fault_code = u; return PyLong_FromLong(_PyJPModule_fault_code); } #endif #ifdef ANDROID static PyObject *PyJPModule_bootstrap(PyObject *module) { // After all the internals are created we can connect the API with the internal module JNIEnv * env = Android_JNI_GetEnv(); JPContext_global->attachJVM(env); PyJPModule_installGC(module); PyJPModule_loadResources(module); Py_RETURN_NONE; } #endif static PyMethodDef moduleMethods[] = { // Startup and initialization {"isStarted", (PyCFunction) PyJPModule_isStarted, METH_NOARGS, ""}, #ifdef ANDROID {"bootstrap", (PyCFunction) PyJPModule_bootstrap, METH_NOARGS, ""}, #else {"startup", (PyCFunction) PyJPModule_startup, METH_VARARGS, ""}, // {"attach", (PyCFunction) (&PyJPModule_attach), METH_VARARGS, ""}, {"shutdown", (PyCFunction) PyJPModule_shutdown, METH_VARARGS, ""}, #endif {"_getClass", (PyCFunction) PyJPModule_getClass, METH_O, ""}, {"_hasClass", (PyCFunction) PyJPModule_hasClass, METH_O, ""}, {"_newArrayType", (PyCFunction) PyJPModule_newArrayType, METH_VARARGS, ""}, {"_collect", (PyCFunction) PyJPModule_collect, METH_VARARGS, ""}, {"gcStats", (PyCFunction) PyJPModule_gcStats, METH_NOARGS, ""}, // Threading {"isThreadAttachedToJVM", (PyCFunction) PyJPModule_isThreadAttached, METH_NOARGS, ""}, #ifndef ANDROID {"attachThreadToJVM", (PyCFunction) PyJPModule_attachThread, METH_NOARGS, ""}, {"detachThreadFromJVM", (PyCFunction) PyJPModule_detachThread, METH_NOARGS, ""}, {"attachThreadAsDaemon", (PyCFunction) PyJPModule_attachThreadAsDaemon, METH_NOARGS, ""}, #endif //{"dumpJVMStats", (PyCFunction) (&PyJPModule_dumpJVMStats), METH_NOARGS, ""}, {"convertToDirectBuffer", (PyCFunction) PyJPModule_convertToDirectByteBuffer, METH_O, ""}, {"arrayFromBuffer", (PyCFunction) PyJPModule_arrayFromBuffer, METH_VARARGS, ""}, {"enableStacktraces", (PyCFunction) PyJPModule_enableStacktraces, METH_O, ""}, {"isPackage", (PyCFunction) PyJPModule_isPackage, METH_O, ""}, {"trace", (PyCFunction) PyJPModule_trace, METH_O, ""}, #ifdef JP_INSTRUMENTATION {"fault", (PyCFunction) PyJPModule_fault, METH_O, ""}, #endif {"examine", (PyCFunction) examine, METH_O, ""}, // sentinel {NULL} }; static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "_jpype", "jpype module", -1, moduleMethods, }; PyObject *PyJPModule = NULL; JPContext* JPContext_global = NULL; PyMODINIT_FUNC PyInit__jpype() { JP_PY_TRY("PyInit__jpype"); JPContext_global = new JPContext(); #if PY_VERSION_HEX<0x03070000 // This is required for python versions prior to 3.7. // It is called by the python initialization starting from 3.7, // but is safe to call afterwards. Starting 3.9 this issues a // deprecation warning. PyEval_InitThreads(); #endif // Initialize the module (depends on python version) PyObject* module = PyModule_Create(&moduledef); // PyJPModule = module; Py_INCREF(module); PyJPModule = module; PyModule_AddStringConstant(module, "__version__", "1.3.0"); // Our module will be used for PyFrame object and it is a requirement that // we have a builtins in our dictionary. PyObject *builtins = PyEval_GetBuiltins(); Py_INCREF(builtins); PyModule_AddObject(module, "__builtins__", builtins); PyJPClassMagic = PyDict_New(); // Initialize each of the python extension types PyJPClass_initType(module); PyJPObject_initType(module); PyJPArray_initType(module); PyJPBuffer_initType(module); PyJPField_initType(module); PyJPMethod_initType(module); PyJPNumber_initType(module); PyJPMonitor_initType(module); PyJPProxy_initType(module); PyJPClassHints_initType(module); PyJPPackage_initType(module); PyJPChar_initType(module); _PyJPModule_trace = true; return module; JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } #ifdef __cplusplus } #endif void PyJPModule_rethrow(const JPStackInfo& info) { JP_TRACE_IN("PyJPModule_rethrow"); JP_TRACE(info.getFile(), info.getLine()); try { throw; } catch (JPypeException& ex) { ex.from(info); // this likely wont be necessary, but for now we will add the entry point. ex.toPython(); return; } catch (std::exception &ex) { PyErr_Format(PyExc_RuntimeError, "Unhandled C++ exception occurred: %s", ex.what()); return; } catch (...) { PyErr_Format(PyExc_RuntimeError, "Unhandled C++ exception occurred"); return; } JP_TRACE_OUT; // GCOVR_EXCL_LINE } static PyObject *PyJPModule_convertBuffer(JPPyBuffer& buffer, PyObject *dtype) { JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); Py_buffer& view = buffer.getView(); // Okay two possibilities here. We have a valid dtype specified, // or we need to figure it out from the buffer. JPClass *cls = NULL; if (view.suboffsets != NULL && view.suboffsets[view.ndim - 1] > 0) { PyErr_Format(PyExc_TypeError, "last dimension is not contiguous"); return NULL; } // First lets find out what we are unpacking Py_ssize_t itemsize = view.itemsize; char *format = view.format; if (format == NULL) format = "B"; // Standard size for 'l' is 4 in docs, but numpy uses format 'l' for long long if (itemsize == 8 && format[0] == 'l') format = "q"; if (itemsize == 8 && format[0] == 'L') format = "Q"; if (dtype != NULL && dtype != Py_None ) { cls = PyJPClass_getJPClass(dtype); if (cls == NULL || !cls->isPrimitive()) { PyErr_Format(PyExc_TypeError, "'%s' is not a Java primitive type", Py_TYPE(dtype)->tp_name); return NULL; } } else { switch (format[0]) { case '?': cls = context->_boolean; case 'c': break; case 'b': cls = context->_byte; case 'B': break; case 'h': cls = context->_short; break; case 'H': break; case 'i': case 'l': cls = context->_int; break; case 'I': case 'L': break; case 'q': cls = context->_long; break; case 'Q': break; case 'f': cls = context->_float; break; case 'd': cls = context->_double; break; case 'n': case 'N': case 'P': default: break; } if (cls == NULL) { PyErr_Format(PyExc_TypeError, "'%s' type code not supported without dtype specified", format); return NULL; } } // Now we have a valid format code, so next lets get a converter for // the type. JPPrimitiveType *pcls = (JPPrimitiveType *) cls; // Convert the shape Py_ssize_t subs = 1; Py_ssize_t base = 1; jintArray jdims = (jintArray) context->_int->newArrayOf(frame, view.ndim); if (view.shape != NULL) { JPPrimitiveArrayAccessor accessor(frame, jdims, &JPJavaFrame::GetIntArrayElements, &JPJavaFrame::ReleaseIntArrayElements); jint *a = accessor.get(); for (int i = 0; i < view.ndim; ++i) { a[i] = view.shape[i]; } accessor.commit(); for (int i = 0; i < view.ndim - 1; ++i) { subs *= view.shape[i]; } base = view.shape[view.ndim - 1]; } else { if (view.ndim > 1) { PyErr_Format(PyExc_TypeError, "buffer dims inconsistent"); return NULL; } base = view.len / view.itemsize; } return pcls->newMultiArray(frame, buffer, subs, base, (jobject) jdims); } #ifdef JP_INSTRUMENTATION int PyJPModuleFault_check(uint32_t code) { return (code == _PyJPModule_fault_code); } void PyJPModuleFault_throw(uint32_t code) { if (code == _PyJPModule_fault_code) { _PyJPModule_fault_code = -1; JP_RAISE(PyExc_SystemError, "fault"); } } #endif void PyJPModule_installGC(PyObject* module) { // Get the Python garbage collector JPPyObject gc = JPPyObject::call(PyImport_ImportModule("gc")); // Find the callbacks JPPyObject callbacks = JPPyObject::call(PyObject_GetAttrString(gc.get(), "callbacks")); // Hook up our callback JPPyObject collect = JPPyObject::call(PyObject_GetAttrString(module, "_collect")); PyList_Append(callbacks.get(), collect.get()); JP_PY_CHECK(); } jpype-1.3.0/native/python/pyjp_monitor.cpp000066400000000000000000000070671405671516700207340ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "pyjp.h" #include "jp_monitor.h" #include "jp_stringtype.h" #ifdef __cplusplus extern "C" { #endif struct PyJPMonitor { PyObject_HEAD JPMonitor *m_Monitor; } ; static int PyJPMonitor_init(PyJPMonitor *self, PyObject *args) { JP_PY_TRY("PyJPMonitor_init"); self->m_Monitor = NULL; JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); PyObject* value; if (!PyArg_ParseTuple(args, "O", &value)) return -1; JPValue *v1 = PyJPValue_getJavaSlot(value); if (v1 == NULL) { PyErr_SetString(PyExc_TypeError, "Java object is required."); return -1; } if (v1->getClass() == context->_java_lang_String) { PyErr_SetString(PyExc_TypeError, "Java strings cannot be used to synchronize."); return -1; } if ((v1->getClass())->isPrimitive()) { PyErr_SetString(PyExc_TypeError, "Java primitives cannot be used to synchronize."); return -1; } if (v1->getValue().l == NULL) { PyErr_SetString(PyExc_TypeError, "Java null cannot be used to synchronize."); return -1; } self->m_Monitor = new JPMonitor(context, v1->getValue().l); return 0; JP_PY_CATCH(-1); } static void PyJPMonitor_dealloc(PyJPMonitor *self) { JP_PY_TRY("PyJPMonitor_dealloc"); delete self->m_Monitor; Py_TYPE(self)->tp_free(self); JP_PY_CATCH(); // GCOVR_EXCL_LINE } static PyObject *PyJPMonitor_str(PyJPMonitor *self) { JP_PY_TRY("PyJPMonitor_str"); return PyUnicode_FromFormat(""); JP_PY_CATCH(NULL); } static PyObject *PyJPMonitor_enter(PyJPMonitor *self, PyObject *args) { JP_PY_TRY("PyJPMonitor_enter"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); self->m_Monitor->enter(); Py_RETURN_NONE; JP_PY_CATCH(NULL); } static PyObject *PyJPMonitor_exit(PyJPMonitor *self, PyObject *args) { JP_PY_TRY("PyJPMonitor_exit"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); self->m_Monitor->exit(); Py_RETURN_NONE; JP_PY_CATCH(NULL); } static PyMethodDef monitorMethods[] = { {"__enter__", (PyCFunction) (&PyJPMonitor_enter), METH_NOARGS, ""}, {"__exit__", (PyCFunction) (&PyJPMonitor_exit), METH_VARARGS, ""}, {NULL}, }; static PyType_Slot monitorSlots[] = { { Py_tp_init, (void*) PyJPMonitor_init}, { Py_tp_dealloc, (void*) PyJPMonitor_dealloc}, { Py_tp_str, (void*) PyJPMonitor_str}, { Py_tp_methods, (void*) &monitorMethods}, {0} }; PyType_Spec PyJPMonitorSpec = { "_jpype._JMonitor", sizeof (PyJPMonitor), 0, Py_TPFLAGS_DEFAULT, monitorSlots }; PyTypeObject* PyJPMonitor_Type = NULL; #ifdef __cplusplus } #endif void PyJPMonitor_initType(PyObject* module) { PyJPMonitor_Type = (PyTypeObject*) PyType_FromSpec(&PyJPMonitorSpec); JP_PY_CHECK(); // GCOVR_EXCL_LINE PyModule_AddObject(module, "_JMonitor", (PyObject*) PyJPMonitor_Type); JP_PY_CHECK(); // GCOVR_EXCL_LINE } jpype-1.3.0/native/python/pyjp_number.cpp000066400000000000000000000323321405671516700205260ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "pyjp.h" #include "jp_boxedtype.h" static bool isNull(PyObject *self) { JPValue *javaSlot = PyJPValue_getJavaSlot(self); if (javaSlot != NULL && !javaSlot->getClass()->isPrimitive() && javaSlot->getValue().l == 0) return true; return false; } #ifdef __cplusplus extern "C" { #endif static PyObject *PyJPNumber_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { JP_PY_TRY("PyJPNumber_new", type); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); JPClass *cls = (JPClass*) PyJPClass_getJPClass((PyObject*) type); if (cls == NULL) JP_RAISE(PyExc_TypeError, "Class type incorrect"); jvalue val; // One argument tries Java conversion first if (PyTuple_Size(args) == 1) { PyObject *arg = PyTuple_GetItem(args, 0); JPMatch match(&frame, arg); cls->findJavaConversion(match); if (match.type >= JPMatch::_implicit) { // Disable OverrangeError match.type = JPMatch::_exact; val = match.convert(); PyObject *obj = cls->convertToPythonObject(frame, val, true).keep(); return obj; } } if (PyObject_IsSubclass((PyObject*) type, (PyObject*) & PyLong_Type)) { JPPyObject self = JPPyObject::call(PyLong_Type.tp_new(&PyLong_Type, args, kwargs)); JPMatch match(&frame, self.get()); cls->findJavaConversion(match); match.type = JPMatch::_exact; val = match.convert(); return cls->convertToPythonObject(frame, val, true).keep(); } else if (PyObject_IsSubclass((PyObject*) type, (PyObject*) & PyFloat_Type)) { JPPyObject self = JPPyObject::call(PyFloat_Type.tp_new(&PyFloat_Type, args, kwargs)); JPMatch match(&frame, self.get()); cls->findJavaConversion(match); match.type = JPMatch::_exact; val = match.convert(); return cls->convertToPythonObject(frame, val, true).keep(); } else { PyErr_Format(PyExc_TypeError, "Type '%s' is not a number class", type->tp_name); return NULL; } JP_PY_CATCH(NULL); } static PyObject *PyJPNumberLong_int(PyObject *self) { JP_PY_TRY("PyJPNumberLong_int"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); if (!isNull(self)) return PyLong_Type.tp_as_number->nb_int(self); PyErr_SetString(PyExc_TypeError, "cast of null pointer would return non-int"); JP_PY_CATCH(NULL); } static PyObject *PyJPNumberLong_float(PyObject *self) { JP_PY_TRY("PyJPNumberLong_float"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); if (!isNull(self)) return PyLong_Type.tp_as_number->nb_float(self); PyErr_SetString(PyExc_TypeError, "cast of null pointer would return non-float"); JP_PY_CATCH(NULL); } static PyObject *PyJPNumberFloat_int(PyObject *self) { JP_PY_TRY("PyJPNumberFloat_int"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); if (!isNull(self)) return PyFloat_Type.tp_as_number->nb_int(self); PyErr_SetString(PyExc_TypeError, "cast of null pointer would return non-int"); JP_PY_CATCH(NULL); } static PyObject *PyJPNumberFloat_float(PyObject *self) { JP_PY_TRY("PyJPNumberFloat_float"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); if (!isNull(self)) return PyFloat_Type.tp_as_number->nb_float(self); PyErr_SetString(PyExc_TypeError, "cast of null pointer would return non-float"); JP_PY_CATCH(NULL); } static PyObject *PyJPNumberLong_str(PyObject *self) { JP_PY_TRY("PyJPNumberLong_str"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); if (isNull(self)) return Py_TYPE(Py_None)->tp_str(Py_None); return PyLong_Type.tp_str(self); JP_PY_CATCH(NULL); } static PyObject *PyJPNumberFloat_str(PyObject *self) { JP_PY_TRY("PyJPNumberFloat_str"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); if (isNull(self)) return Py_TYPE(Py_None)->tp_str(Py_None); return PyFloat_Type.tp_str(self); JP_PY_CATCH(NULL); } static PyObject *PyJPNumberLong_repr(PyObject *self) { JP_PY_TRY("PyJPNumberLong_repr"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); if (isNull(self)) return Py_TYPE(Py_None)->tp_str(Py_None); return PyLong_Type.tp_repr(self); JP_PY_CATCH(NULL); } static PyObject *PyJPNumberFloat_repr(PyObject *self) { JP_PY_TRY("PyJPNumberFloat_repr"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); if (isNull(self)) return Py_TYPE(Py_None)->tp_str(Py_None); return PyFloat_Type.tp_repr(self); JP_PY_CATCH(NULL); } static const char* op_names[] = { "<", "<=", "==", "!=", ">", ">=" }; static PyObject *PyJPNumberLong_compare(PyObject *self, PyObject *other, int op) { JP_PY_TRY("PyJPNumberLong_compare"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); if (isNull(self)) { if (op == Py_EQ) return PyBool_FromLong(other == Py_None); if (op == Py_NE) return PyBool_FromLong(other != Py_None); PyErr_Format(PyExc_TypeError, "'%s' not supported with null pointer", op_names[op]); JP_RAISE_PYTHON(); } if (!PyNumber_Check(other)) { PyObject *out = Py_NotImplemented; Py_INCREF(out); return out; } return PyLong_Type.tp_richcompare(self, other, op); JP_PY_CATCH(NULL); } static PyObject *PyJPNumberFloat_compare(PyObject *self, PyObject *other, int op) { JP_PY_TRY("PyJPNumberFloat_compare"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); if (isNull(self)) { if (op == Py_EQ) return PyBool_FromLong(other == Py_None); if (op == Py_NE) return PyBool_FromLong(other != Py_None); PyErr_Format(PyExc_TypeError, "'%s' not supported with null pointer", op_names[op]); JP_RAISE_PYTHON(); } if (!PyNumber_Check(other)) // || Py_TYPE(other) == (PyTypeObject*) _JChar) { PyObject *out = Py_NotImplemented; Py_INCREF(out); return out; } return PyFloat_Type.tp_richcompare(self, other, op); JP_PY_CATCH(NULL); } static Py_hash_t PyJPNumberLong_hash(PyObject *self) { JP_PY_TRY("PyJPNumberLong_hash"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); JPValue *javaSlot = PyJPValue_getJavaSlot(self); if (javaSlot == NULL) return Py_TYPE(Py_None)->tp_hash(Py_None); if (!javaSlot->getClass()->isPrimitive()) { jobject o = javaSlot->getJavaObject(); if (o == NULL) return Py_TYPE(Py_None)->tp_hash(Py_None); } return PyLong_Type.tp_hash(self); JP_PY_CATCH(0); } static Py_hash_t PyJPNumberFloat_hash(PyObject *self) { JP_PY_TRY("PyJPNumberFloat_hash"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); JPValue *javaSlot = PyJPValue_getJavaSlot(self); if (javaSlot == NULL) return Py_TYPE(Py_None)->tp_hash(Py_None); if (!javaSlot->getClass()->isPrimitive()) { jobject o = javaSlot->getJavaObject(); if (o == NULL) return Py_TYPE(Py_None)->tp_hash(Py_None); } return PyFloat_Type.tp_hash(self); JP_PY_CATCH(0); } static PyObject *PyJPBoolean_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { JP_PY_TRY("PyJPBoolean_new", type); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); JPPyObject self; if (PyTuple_Size(args) != 1) { PyErr_SetString(PyExc_TypeError, "Requires one argument"); return NULL; } int i = PyObject_IsTrue(PyTuple_GetItem(args, 0)); PyObject *args2 = PyTuple_Pack(1, PyLong_FromLong(i)); self = JPPyObject::call(PyLong_Type.tp_new(type, args2, kwargs)); Py_DECREF(args2); JPClass *cls = PyJPClass_getJPClass((PyObject*) type); if (cls == NULL) { PyErr_SetString(PyExc_TypeError, "Class type incorrect"); return NULL; } JPMatch match(&frame, self.get()); cls->findJavaConversion(match); jvalue val = match.convert(); PyJPValue_assignJavaSlot(frame, self.get(), JPValue(cls, val)); JP_TRACE("new", self.get()); return self.keep(); JP_PY_CATCH(NULL); } static PyObject* PyJPBoolean_str(PyObject* self) { JP_PY_TRY("PyJPBoolean_str", self); if (isNull(self)) return Py_TYPE(Py_None)->tp_str(Py_None); if (PyLong_AsLong(self) == 0) return Py_TYPE(Py_False)->tp_str(Py_False); return Py_TYPE(Py_True)->tp_str(Py_True); JP_PY_CATCH(NULL); } static PyType_Slot numberLongSlots[] = { {Py_tp_new, (void*) &PyJPNumber_new}, {Py_tp_getattro, (void*) &PyJPValue_getattro}, {Py_tp_setattro, (void*) &PyJPValue_setattro}, {Py_nb_int, (void*) &PyJPNumberLong_int}, {Py_nb_float, (void*) &PyJPNumberLong_float}, {Py_tp_str, (void*) &PyJPNumberLong_str}, {Py_tp_repr, (void*) &PyJPNumberLong_repr}, {Py_tp_hash, (void*) &PyJPNumberLong_hash}, {Py_tp_richcompare, (void*) &PyJPNumberLong_compare}, {0} }; PyTypeObject *PyJPNumberLong_Type = NULL; PyType_Spec numberLongSpec = { "_jpype._JNumberLong", 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, numberLongSlots }; static PyType_Slot numberFloatSlots[] = { {Py_tp_new, (void*) &PyJPNumber_new}, {Py_tp_getattro, (void*) &PyJPValue_getattro}, {Py_tp_setattro, (void*) &PyJPValue_setattro}, {Py_nb_int, (void*) &PyJPNumberFloat_int}, {Py_nb_float, (void*) &PyJPNumberFloat_float}, {Py_tp_str, (void*) &PyJPNumberFloat_str}, {Py_tp_repr, (void*) &PyJPNumberFloat_repr}, {Py_tp_hash, (void*) &PyJPNumberFloat_hash}, {Py_tp_richcompare, (void*) &PyJPNumberFloat_compare}, {0} }; PyTypeObject *PyJPNumberFloat_Type = NULL; PyType_Spec numberFloatSpec = { "_jpype._JNumberFloat", 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, numberFloatSlots }; static PyType_Slot numberBooleanSlots[] = { {Py_tp_new, (void*) PyJPBoolean_new}, {Py_tp_getattro, (void*) PyJPValue_getattro}, {Py_tp_setattro, (void*) PyJPValue_setattro}, {Py_tp_str, (void*) PyJPBoolean_str}, {Py_tp_repr, (void*) PyJPBoolean_str}, {Py_nb_int, (void*) PyJPNumberLong_int}, {Py_nb_float, (void*) PyJPNumberLong_float}, {Py_tp_hash, (void*) PyJPNumberLong_hash}, {Py_tp_richcompare, (void*) PyJPNumberLong_compare}, {0} }; PyTypeObject *PyJPNumberBool_Type = NULL; PyType_Spec numberBooleanSpec = { "_jpype._JBoolean", 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, numberBooleanSlots }; #ifdef __cplusplus } #endif void PyJPNumber_initType(PyObject* module) { PyObject *bases; bases = PyTuple_Pack(2, &PyLong_Type, PyJPObject_Type); PyJPNumberLong_Type = (PyTypeObject*) PyJPClass_FromSpecWithBases(&numberLongSpec, bases); Py_DECREF(bases); JP_PY_CHECK(); // GCOVR_EXCL_LINE PyModule_AddObject(module, "_JNumberLong", (PyObject*) PyJPNumberLong_Type); JP_PY_CHECK(); // GCOVR_EXCL_LINE bases = PyTuple_Pack(2, &PyFloat_Type, PyJPObject_Type); PyJPNumberFloat_Type = (PyTypeObject*) PyJPClass_FromSpecWithBases(&numberFloatSpec, bases); Py_DECREF(bases); JP_PY_CHECK(); // GCOVR_EXCL_LINE PyModule_AddObject(module, "_JNumberFloat", (PyObject*) PyJPNumberFloat_Type); JP_PY_CHECK(); // GCOVR_EXCL_LINE bases = PyTuple_Pack(1, &PyLong_Type, PyJPObject_Type); PyJPNumberBool_Type = (PyTypeObject*) PyJPClass_FromSpecWithBases(&numberBooleanSpec, bases); Py_DECREF(bases); JP_PY_CHECK(); // GCOVR_EXCL_LINE PyModule_AddObject(module, "_JBoolean", (PyObject*) PyJPNumberBool_Type); JP_PY_CHECK(); // GCOVR_EXCL_LINE } JPPyObject PyJPNumber_create(JPJavaFrame &frame, JPPyObject& wrapper, const JPValue& value) { JPContext *context = frame.getContext(); // Bools are not numbers in Java if (value.getClass() == context->_java_lang_Boolean) { jlong l = 0; if (value.getValue().l != 0) l = frame.CallBooleanMethodA(value.getJavaObject(), context->_java_lang_Boolean->m_BooleanValueID, 0); PyObject *args = PyTuple_Pack(1, PyLong_FromLongLong(l)); return JPPyObject::call(PyLong_Type.tp_new((PyTypeObject*) wrapper.get(), args, NULL)); } if (PyObject_IsSubclass(wrapper.get(), (PyObject*) & PyLong_Type)) { jlong l = 0; if (value.getValue().l != 0) { JPBoxedType* jb = (JPBoxedType*) value.getClass(); l = frame.CallLongMethodA(value.getJavaObject(), jb->m_LongValueID, 0); } PyObject *args = PyTuple_Pack(1, PyLong_FromLongLong(l)); return JPPyObject::call(PyLong_Type.tp_new((PyTypeObject*) wrapper.get(), args, NULL)); } if (PyObject_IsSubclass(wrapper.get(), (PyObject*) & PyFloat_Type)) { jdouble l = 0; if (value.getValue().l != 0) { JPBoxedType* jb = (JPBoxedType*) value.getClass(); l = frame.CallDoubleMethodA(value.getJavaObject(), jb->m_DoubleValueID, 0); } PyObject *args = PyTuple_Pack(1, PyFloat_FromDouble(l)); return JPPyObject::call(PyFloat_Type.tp_new((PyTypeObject*) wrapper.get(), args, NULL)); } JP_RAISE(PyExc_TypeError, "unable to convert"); //GCOVR_EXCL_LINE } jpype-1.3.0/native/python/pyjp_object.cpp000066400000000000000000000277651405671516700205220ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "pyjp.h" #include #ifdef __cplusplus extern "C" { #endif static PyObject *PyJPObject_new(PyTypeObject *type, PyObject *pyargs, PyObject *kwargs) { JP_PY_TRY("PyJPObject_new"); // Get the Java class from the type. JPClass *cls = PyJPClass_getJPClass((PyObject*) type); if (cls == NULL) { PyErr_SetString(PyExc_TypeError, "Java class type is incorrect"); return NULL; } // Create an instance (this may fail) JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); JPPyObjectVector args(pyargs); JPValue jv = cls->newInstance(frame, args); // If it succeeded then allocate memory PyObject *self = type->tp_alloc(type, 0); JP_PY_CHECK(); JP_FAULT_RETURN("PyJPObject_init.null", self); PyJPValue_assignJavaSlot(frame, self, jv); return self; JP_PY_CATCH(NULL); } static PyObject *PyJPObject_compare(PyObject *self, PyObject *other, int op) { JP_PY_TRY("PyJPObject_compare"); if (op == Py_NE) { PyObject *ret = PyJPObject_compare(self, other, Py_EQ); if (ret == NULL) return NULL; int rc = (ret == Py_False); Py_DECREF(ret); return PyBool_FromLong(rc); } if (op != Py_EQ) { PyObject *out = Py_NotImplemented; Py_INCREF(out); return out; } JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); JPValue *javaSlot0 = PyJPValue_getJavaSlot(self); JPValue *javaSlot1 = PyJPValue_getJavaSlot(other); // First slot is Null if (javaSlot0 == NULL || javaSlot0->getValue().l == NULL) { if (javaSlot1 == NULL) return PyBool_FromLong(other == Py_None); if (javaSlot1->getClass()->isPrimitive()) Py_RETURN_FALSE; if (javaSlot1->getValue().l == NULL) Py_RETURN_TRUE; Py_RETURN_FALSE; } // Check second slot is Null if (other == Py_None) Py_RETURN_FALSE; if (javaSlot1 == NULL) { // This block seems like a giant waste as there are very few cases in which // a converted object would ever satisfy equals. But this was the original // logic in JPype so we will try to match it. JPMatch match(&frame, other); javaSlot0->getClass()->findJavaConversion(match); if (match.type < JPMatch::_implicit) Py_RETURN_FALSE; return PyBool_FromLong(frame.equals(javaSlot0->getValue().l, match.convert().l)); } if (javaSlot1->getClass()->isPrimitive()) Py_RETURN_FALSE; if (javaSlot1->getValue().l == NULL) Py_RETURN_FALSE; return PyBool_FromLong(frame.equals(javaSlot0->getValue().l, javaSlot1->getValue().l)); JP_PY_CATCH(0); // GCOVR_EXCL_LINE } static PyObject *PyJPComparable_compare(PyObject *self, PyObject *other, int op) { JP_PY_TRY("PyJPComparable_compare"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); JPValue *javaSlot0 = PyJPValue_getJavaSlot(self); JPValue *javaSlot1 = PyJPValue_getJavaSlot(other); bool null0 = false; bool null1 = false; // First slot is Null if (self == Py_None || javaSlot0 == NULL || (!javaSlot0->getClass()->isPrimitive() && javaSlot0->getValue().l == NULL)) null0 = true; if (other == Py_None || (javaSlot1 != NULL && !javaSlot1->getClass()->isPrimitive() && javaSlot1->getValue().l == NULL)) null1 = true; jobject obj0 = NULL; jobject obj1 = NULL; if (!null0) obj0 = javaSlot0->getValue().l; if (!null0 && !null1 && javaSlot1 == NULL) { // Okay here is the hard part. We need to figure out what type // of object to create to make them comparable. We can't assume // the most derived type because some classes inherit comparable // and that would require the derived type. We have to find // the first super class that implements Comparable. Further, // because of type erasure we can't actually get. JPClass *cls2 = javaSlot0->getClass(); JPMatch match(&frame, other); while (cls2 != NULL && !cls2->findJavaConversion(match) && !JPModifier::isComparable(cls2->getModifiers())) cls2 = cls2->getSuperClass(); // This should never happen. if (cls2 == NULL) { PyObject *out = Py_NotImplemented; Py_INCREF(out); return out; } obj1 = match.convert().l; } else if (!null1 && javaSlot1 != NULL) obj1 = javaSlot1->getValue().l; switch (op) { case Py_EQ: if (null0 && null1) Py_RETURN_TRUE; if (null0 || null1) Py_RETURN_FALSE; return PyBool_FromLong(frame.compareTo(obj0, obj1) == 0); case Py_NE: if (null0 && null1) Py_RETURN_FALSE; if (null0 || null1) Py_RETURN_TRUE; return PyBool_FromLong(frame.compareTo(obj0, obj1) != 0); case Py_LT: if (null0 || null1) break; return PyBool_FromLong(frame.compareTo(obj0, obj1) < 0); case Py_LE: if (null0 || null1) break; return PyBool_FromLong(frame.compareTo(obj0, obj1) <= 0); case Py_GT: if (null0 || null1) break; return PyBool_FromLong(frame.compareTo(obj0, obj1) > 0); case Py_GE: if (null0 || null1) break; return PyBool_FromLong(frame.compareTo(obj0, obj1) >= 0); } PyErr_SetString(PyExc_ValueError, "can't compare null"); JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } static Py_hash_t PyJPObject_hash(PyObject *obj) { JP_PY_TRY("PyJPObject_hash"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); JPValue *javaSlot = PyJPValue_getJavaSlot(obj); if (javaSlot == NULL) return Py_TYPE(Py_None)->tp_hash(Py_None); jobject o = javaSlot->getJavaObject(); if (o == NULL) return Py_TYPE(Py_None)->tp_hash(Py_None); return frame.hashCode(o); JP_PY_CATCH(0); } static PyObject *PyJPObject_repr(PyObject *self) { JP_PY_TRY("PyJPObject_repr"); return PyUnicode_FromFormat("", Py_TYPE(self)->tp_name); JP_PY_CATCH(0); // GCOVR_EXCL_LINE } static PyType_Slot objectSlots[] = { {Py_tp_new, (void*) &PyJPObject_new}, {Py_tp_free, (void*) &PyJPValue_free}, {Py_tp_getattro, (void*) &PyJPValue_getattro}, {Py_tp_setattro, (void*) &PyJPValue_setattro}, {Py_tp_str, (void*) &PyJPValue_str}, {Py_tp_repr, (void*) &PyJPObject_repr}, {Py_tp_richcompare, (void*) &PyJPObject_compare}, {Py_tp_hash, (void*) &PyJPObject_hash}, {0} }; PyTypeObject *PyJPObject_Type = NULL; static PyType_Spec objectSpec = { "_jpype._JObject", 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, objectSlots }; static PyObject *PyJPException_new(PyTypeObject *type, PyObject *pyargs, PyObject *kwargs) { JP_PY_TRY("PyJPException_new"); // Get the Java class from the type. JPClass *cls = PyJPClass_getJPClass((PyObject*) type); if (cls == NULL) { // GCOVR_EXCL_START PyErr_SetString(PyExc_TypeError, "Java class type is incorrect"); return NULL; } // GCOVR_EXCL_STOP // Special constructor path for Exceptions JPPyObjectVector args(pyargs); if (args.size() == 2 && args[0] == _JObjectKey) return ((PyTypeObject*) PyExc_BaseException)->tp_new(type, args[1], kwargs); // Create an instance (this may fail) JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); JPValue jv = cls->newInstance(frame, args); // Exception must be constructed with the BaseException_new PyObject *self = ((PyTypeObject*) PyExc_BaseException)->tp_new(type, pyargs, kwargs); JP_PY_CHECK(); JP_FAULT_RETURN("PyJPException_init.null", self); PyJPValue_assignJavaSlot(frame, self, jv); return self; JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } static int PyJPException_init(PyObject *self, PyObject *pyargs, PyObject *kwargs) { JP_PY_TRY("PyJPException_init"); JPPyObjectVector args(pyargs); if (args.size() == 2 && args[0] == _JObjectKey) return ((PyTypeObject*) PyExc_BaseException)->tp_init(self, args[1], kwargs); // Exception must be constructed with the BaseException_new return ((PyTypeObject*) PyExc_BaseException)->tp_init(self, pyargs, kwargs); JP_PY_CATCH(-1); // GCOVR_EXCL_LINE } static PyObject* PyJPException_expandStacktrace(PyObject* self) { JP_PY_TRY("PyJPModule_expandStackTrace"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); JPValue *val = PyJPValue_getJavaSlot(self); // These two are loop invariants and must match each time jthrowable th = (jthrowable) val->getValue().l; JPPyObject exc = JPPyObject::use(self); PyJPException_normalize(frame, exc, th, NULL); Py_RETURN_NONE; JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } PyObject *PyJPException_args(PyBaseExceptionObject *self) { if (self->args == NULL) Py_RETURN_NONE; // GCOVR_EXCL_LINE Py_INCREF(self->args); return self->args; } static PyMethodDef exceptionMethods[] = { {"_expandStacktrace", (PyCFunction) PyJPException_expandStacktrace, METH_NOARGS, ""}, {NULL}, }; static PyGetSetDef exceptionGetSets[] = { {"_args", (getter) PyJPException_args, NULL, ""}, {0} }; PyTypeObject *PyJPException_Type = NULL; static PyType_Slot excSlots[] = { {Py_tp_new, (void*) &PyJPException_new}, {Py_tp_init, (void*) &PyJPException_init}, {Py_tp_str, (void*) &PyJPValue_str}, {Py_tp_getattro, (void*) &PyJPValue_getattro}, {Py_tp_setattro, (void*) &PyJPValue_setattro}, {Py_tp_methods, exceptionMethods}, {Py_tp_getset, exceptionGetSets}, {0} }; static PyType_Spec excSpec = { "_jpype._JException", 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, excSlots }; static PyType_Slot comparableSlots[] = { {Py_tp_richcompare, (void*) &PyJPComparable_compare}, {Py_tp_hash, (void*) &PyJPObject_hash}, {0} }; PyTypeObject *PyJPComparable_Type = NULL; static PyType_Spec comparableSpec = { "_jpype._JComparable", 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, comparableSlots }; #ifdef __cplusplus } #endif void PyJPObject_initType(PyObject* module) { PyJPObject_Type = (PyTypeObject*) PyJPClass_FromSpecWithBases(&objectSpec, NULL); JP_PY_CHECK(); // GCOVR_EXCL_LINE PyModule_AddObject(module, "_JObject", (PyObject*) PyJPObject_Type); JP_PY_CHECK(); // GCOVR_EXCL_LINE JPPyObject bases = JPPyObject::call(PyTuple_Pack(2, PyExc_Exception, PyJPObject_Type)); PyJPException_Type = (PyTypeObject*) PyJPClass_FromSpecWithBases(&excSpec, bases.get()); JP_PY_CHECK(); // GCOVR_EXCL_LINE PyModule_AddObject(module, "_JException", (PyObject*) PyJPException_Type); JP_PY_CHECK(); // GCOVR_EXCL_LINE bases = JPPyObject::call(PyTuple_Pack(1, PyJPObject_Type)); PyJPComparable_Type = (PyTypeObject*) PyJPClass_FromSpecWithBases(&comparableSpec, bases.get()); JP_PY_CHECK(); // GCOVR_EXCL_LINE PyModule_AddObject(module, "_JComparable", (PyObject*) PyJPComparable_Type); JP_PY_CHECK(); // GCOVR_EXCL_LINE } /** * Attach stack frames and causes as required for a Python exception. */ void PyJPException_normalize(JPJavaFrame frame, JPPyObject exc, jthrowable th, jthrowable enclosing) { JP_TRACE_IN("PyJPException_normalize"); JPContext *context = frame.getContext(); while (th != NULL) { // Attach the frame to first JPPyObject trace = PyTrace_FromJavaException(frame, th, enclosing); PyException_SetTraceback(exc.get(), trace.get()); // Check for the next in the cause list enclosing = th; th = frame.getCause(th); if (th == NULL) return; jvalue v; v.l = (jobject) th; JPPyObject next = context->_java_lang_Object->convertToPythonObject(frame, v, false); // This may already be a Python exception JPValue *val = PyJPValue_getJavaSlot(next.get()); if (val == NULL) { PyException_SetCause(exc.get(), next.keep()); return; } next.incref(); // Set cause will steal our reference PyException_SetCause(exc.get(), next.get()); exc = next; } JP_TRACE_OUT; // GCOVR_EXCL_LINE } jpype-1.3.0/native/python/pyjp_package.cpp000066400000000000000000000232501405671516700206300ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "pyjp.h" #include "jp_stringtype.h" #include #ifdef __cplusplus extern "C" { #endif PyTypeObject *PyJPPackage_Type = NULL; static PyObject *PyJPPackage_Dict = NULL; static PyObject *PyJPPackage_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { JP_PY_TRY("PyJPPackage_new"); PyObject *name = NULL; if (!PyArg_Parse(args, "(U)", &name)) return 0; // Check the cache PyObject *obj = PyDict_GetItem(PyJPPackage_Dict, name); if (obj != NULL) { Py_INCREF(obj); return obj; } // Otherwise create a new object PyObject *self = PyModule_Type.tp_new(PyJPPackage_Type, args, NULL); int rc = PyModule_Type.tp_init(self, args, NULL); if (rc != 0) { // If we fail clean up the mess. Py_DECREF(self); return 0; } // Place in cache PyDict_SetItem(PyJPPackage_Dict, name, self); return self; JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } static void dtor(PyObject *self) { JPContext *context = JPContext_global; if (context == NULL || !context->isRunning()) return; jobject jo = (jobject) PyCapsule_GetPointer(self, NULL); if (jo == NULL) return; JPJavaFrame frame = JPJavaFrame::outer(context); frame.DeleteGlobalRef(jo); } static jobject getPackage(JPJavaFrame &frame, PyObject *self) { PyObject *dict = PyModule_GetDict(self); // borrowed PyObject *capsule = PyDict_GetItemString(dict, "_jpackage"); // borrowed jobject jo; if (capsule != NULL) { jo = (jobject) PyCapsule_GetPointer(capsule, NULL); return jo; } const char *name = PyModule_GetName(self); // Attempt to load the object. jo = frame.getPackage(name); // Found it, use it. if (jo != NULL) { jo = frame.NewGlobalRef(jo); capsule = PyCapsule_New(jo, NULL, dtor); PyDict_SetItemString(dict, "_jpackage", capsule); // no steal // Py_DECREF(capsule); return jo; } // Otherwise, this is a bad package. PyErr_Format(PyExc_AttributeError, "Java package '%s' is not valid", name); return NULL; } /** * Get an attribute from the package. * * This will auto load packages and classes when encounter, * but first checks the cache. This acts like an standard Python * module otherwise. * * @param self * @param attr * @return */ static PyObject *PyJPPackage_getattro(PyObject *self, PyObject *attr) { JP_PY_TRY("PyJPPackage_getattro"); if (!PyUnicode_Check(attr)) { PyErr_Format(PyExc_TypeError, "attribute name must be string, not '%s'", Py_TYPE(attr)->tp_name); return NULL; } PyObject *dict = PyModule_GetDict(self); if (dict != NULL) { // Check the cache PyObject *out = PyDict_GetItem(PyModule_GetDict(self), attr); if (out != NULL) { Py_INCREF(out); return out; } } string attrName = JPPyString::asStringUTF8(attr).c_str(); // Check for private attribute if (attrName.compare(0, 2, "__") == 0) return PyObject_GenericGetAttr((PyObject*) self, attr); JPContext* context = JPContext_global; if (!context->isRunning()) { PyErr_Format(PyExc_RuntimeError, "Unable to import '%s.%U' without JVM", PyModule_GetName(self), attr); return 0; } JPJavaFrame frame = JPJavaFrame::outer(context); jobject pkg = getPackage(frame, self); if (pkg == NULL) return NULL; JPPyObject out; jobject obj; try { obj = frame.getPackageObject(pkg, attrName); } catch (JPypeException& ex) { JPPyObject h = JPPyObject::accept(PyObject_GetAttrString(self, "_handler")); // If something fails, we need to go to a handler if (!h.isNull()) { ex.toPython(); JPPyErrFrame err; err.normalize(); err.clear(); JPPyObject tuple0 = JPPyObject::call(PyTuple_Pack(3, self, attr, err.m_ExceptionValue.get())); PyObject *rc = PyObject_Call(h.get(), tuple0.get(), NULL); if (rc == 0) return 0; Py_DECREF(rc); // GCOVR_EXCL_LINE } throw; // GCOVR_EXCL_LINE } if (obj == NULL) { PyErr_Format(PyExc_AttributeError, "Java package '%s' has no attribute '%U'", PyModule_GetName(self), attr); return NULL; } else if (frame.IsInstanceOf(obj, context->_java_lang_Class->getJavaClass())) out = PyJPClass_create(frame, frame.findClass((jclass) obj)); else if (frame.IsInstanceOf(obj, context->_java_lang_String->getJavaClass())) { JPPyObject u = JPPyObject::call(PyUnicode_FromFormat("%s.%U", PyModule_GetName(self), attr)); JPPyObject args = JPPyObject::call(PyTuple_Pack(1, u.get())); out = JPPyObject::call(PyObject_Call((PyObject*) PyJPPackage_Type, args.get(), NULL)); } else { // We should be able to handle Python classes, datafiles, etc, // but that will take time to implement. In principle, things // that are not packages or classes should appear as Buffers or // some other resource type. PyErr_Format(PyExc_AttributeError, "'%U' is unknown object type in Java package", attr); return NULL; } // Cache the item for now PyDict_SetItem(dict, attr, out.get()); // no steal return out.keep(); JP_PY_CATCH(NULL); // GCOVR_EXCL_LINE } /** * This next method is required, I have no clue why. Seems * likely that the default PyObject traverse does not agree * with modules. */ static int PyJPPackage_traverse(PyObject *m, visitproc visit, void *arg) { return PyModule_Type.tp_traverse(m, visit, arg); } static int PyJPPackage_clear(PyObject *m) { return PyModule_Type.tp_clear(m); } static PyObject *PyJPPackage_str(PyObject *self, PyObject *args, PyObject *kwargs) { JP_PY_TRY("PyJPPackage_str"); return PyModule_GetNameObject(self); JP_PY_CATCH(NULL); } static PyObject *PyJPPackage_repr(PyObject *self, PyObject *args, PyObject *kwargs) { JP_PY_TRY("PyJPPackage_repr"); return PyUnicode_FromFormat("", PyModule_GetName(self)); JP_PY_CATCH(NULL); } static PyObject *PyJPPackage_call(PyObject *self, PyObject *args, PyObject *kwargs) { JP_PY_TRY("PyJPPackage_call"); PyErr_Format(PyExc_TypeError, "Package `%s` is not callable.", PyModule_GetName(self)); JP_PY_CATCH(NULL); } static PyObject *PyJPPackage_package(PyObject *self) { return PyUnicode_FromFormat("java"); } static PyObject *PyJPPackage_path(PyObject *self) { return PyList_New(0); } static PyObject *PyJPPackage_dir(PyObject *self) { JP_PY_TRY("PyJPPackage_dir"); JPContext* context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); jobject pkg = getPackage(frame, self); if (pkg == NULL) return NULL; jarray o = frame.getPackageContents(pkg); Py_ssize_t len = frame.GetArrayLength(o); JPPyObject out = JPPyObject::call(PyList_New(len)); for (Py_ssize_t i = 0; i < len; ++i) { string str = frame.toStringUTF8((jstring) frame.GetObjectArrayElement((jobjectArray) o, (jsize) i)); PyList_SetItem(out.get(), i, PyUnicode_FromFormat("%s", str.c_str())); } return out.keep(); JP_PY_CATCH(NULL); } /** * Add redirect for matmul in package modules. * * This will be used to support "java@obj" which will be used * to force cast a Python object into Java. * * @param self * @param other * @return */ static PyObject *PyJPPackage_cast(PyObject *self, PyObject *other) { JP_PY_TRY("PyJPPackage_cast"); PyObject *dict = PyModule_GetDict(self); PyObject* matmul = PyDict_GetItemString(dict, "__matmul__"); if (matmul == NULL) Py_RETURN_NOTIMPLEMENTED; JPPyObject args = JPPyObject::call(PyTuple_Pack(2, self, other)); return PyObject_Call(matmul, args.get(), NULL); JP_PY_CATCH(NULL); } static PyObject *PyJPPackage_castEq(PyObject *self, PyObject *other) { PyErr_Format(PyExc_TypeError, "Matmul equals not support for Java packages"); return NULL; } static PyMethodDef packageMethods[] = { {"__dir__", (PyCFunction) PyJPPackage_dir, METH_NOARGS}, {NULL}, }; static PyGetSetDef packageGetSets[] = { {"__all__", (getter) PyJPPackage_dir, NULL, ""}, {"__name__", (getter) PyJPPackage_str, NULL, ""}, {"__package__", (getter) PyJPPackage_package, NULL, ""}, {"__path__", (getter) PyJPPackage_path, NULL, ""}, {0} }; static PyType_Slot packageSlots[] = { {Py_tp_new, (void*) PyJPPackage_new}, {Py_tp_traverse, (void*) PyJPPackage_traverse}, {Py_tp_clear, (void*) PyJPPackage_clear}, {Py_tp_getattro, (void*) PyJPPackage_getattro}, {Py_tp_str, (void*) PyJPPackage_str}, {Py_tp_repr, (void*) PyJPPackage_repr}, {Py_tp_call, (void*) PyJPPackage_call}, {Py_nb_matrix_multiply, (void*) PyJPPackage_cast}, {Py_nb_inplace_matrix_multiply, (void*) PyJPPackage_castEq}, {Py_tp_methods, (void*) packageMethods}, {Py_tp_getset, (void*) packageGetSets}, {0} }; static PyType_Spec packageSpec = { "_jpype._JPackage", -1, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, packageSlots }; #ifdef __cplusplus } #endif void PyJPPackage_initType(PyObject* module) { // Inherit from module. JPPyObject bases = JPPyObject::call(PyTuple_Pack(1, &PyModule_Type)); packageSpec.basicsize = PyModule_Type.tp_basicsize; PyJPPackage_Type = (PyTypeObject*) PyType_FromSpecWithBases(&packageSpec, bases.get()); JP_PY_CHECK(); PyModule_AddObject(module, "_JPackage", (PyObject*) PyJPPackage_Type); JP_PY_CHECK(); // Set up a dictionary so we can reuse packages PyJPPackage_Dict = PyDict_New(); PyModule_AddObject(module, "_packages", PyJPPackage_Dict); } jpype-1.3.0/native/python/pyjp_proxy.cpp000066400000000000000000000116201405671516700204140ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include #include #include "jpype.h" #include "pyjp.h" #include "jp_proxy.h" #ifdef __cplusplus extern "C" { #endif static PyObject *PyJPProxy_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { JP_PY_TRY("PyJPProxy_new"); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); PyJPProxy *self = (PyJPProxy*) type->tp_alloc(type, 0); JP_PY_CHECK(); // Parse arguments PyObject *target; PyObject *pyintf; int convert = 0; if (!PyArg_ParseTuple(args, "OO|p", &target, &pyintf, &convert)) return NULL; // Pack interfaces if (!PySequence_Check(pyintf)) { PyErr_SetString(PyExc_TypeError, "third argument must be a list of interface"); return NULL; } JPClassList interfaces; JPPySequence intf = JPPySequence::use(pyintf); jlong len = intf.size(); if (len < 1) JP_RAISE(PyExc_TypeError, "at least one interface is required"); for (jlong i = 0; i < len; i++) { JPClass *cls = PyJPClass_getJPClass(intf[i].get()); if (cls == NULL) { PyErr_SetString(PyExc_TypeError, "interfaces must be object class instances"); return NULL; } interfaces.push_back(cls); } if (target == Py_None) self->m_Proxy = new JPProxyDirect(context, self, interfaces); else self->m_Proxy = new JPProxyIndirect(context, self, interfaces); self->m_Target = target; self->m_Convert = (convert != 0); Py_INCREF(target); JP_TRACE("Proxy", self); JP_TRACE("Target", target); return (PyObject*) self; JP_PY_CATCH(NULL); } static int PyJPProxy_traverse(PyJPProxy *self, visitproc visit, void *arg) { Py_VISIT(self->m_Target); return 0; } static int PyJPProxy_clear(PyJPProxy *self) { Py_CLEAR(self->m_Target); return 0; } void PyJPProxy_dealloc(PyJPProxy* self) { JP_PY_TRY("PyJPProxy_dealloc"); delete self->m_Proxy; PyObject_GC_UnTrack(self); PyJPProxy_clear(self); Py_TYPE(self)->tp_free(self); JP_PY_CATCH_NONE(); } static PyObject *PyJPProxy_class(PyJPProxy *self, void *context) { JPJavaFrame frame = JPJavaFrame::outer(self->m_Proxy->getContext()); JPClass* cls = self->m_Proxy->getInterfaces()[0]; return PyJPClass_create(frame, cls).keep(); } static PyObject *PyJPProxy_inst(PyJPProxy *self, void *context) { PyObject *out = self->m_Target; if (out == Py_None) out = (PyObject*) self; Py_INCREF(out); return out; } static PyObject *PyJPProxy_equals(PyJPProxy *self, PyObject *other) { return PyObject_RichCompare((PyObject*) self, other, Py_EQ); } static PyObject *PyJPProxy_hash(PyJPProxy *self) { if (self->m_Target != Py_None) return PyLong_FromLong((int) PyObject_Hash(self->m_Target)); return PyLong_FromLong((int) PyObject_Hash((PyObject*) self)); } static PyObject *PyJPProxy_toString(PyJPProxy *self) { if (self->m_Target != Py_None) return PyObject_Str(self->m_Target); return PyObject_Str((PyObject*) self); } static PyMethodDef proxyMethods[] = { {"equals", (PyCFunction) (&PyJPProxy_equals), METH_O, ""}, {"hashCode", (PyCFunction) (&PyJPProxy_hash), METH_NOARGS, ""}, {"toString", (PyCFunction) (&PyJPProxy_toString), METH_NOARGS, ""}, {NULL}, }; static PyGetSetDef proxyGetSets[] = { {"__javainst__", (getter) PyJPProxy_inst, NULL, ""}, {"__javaclass__", (getter) PyJPProxy_class, NULL, ""}, {0} }; static PyType_Slot proxySlots[] = { { Py_tp_new, (void*) PyJPProxy_new}, { Py_tp_dealloc, (void*) PyJPProxy_dealloc}, { Py_tp_traverse, (void*) PyJPProxy_traverse}, { Py_tp_clear, (void*) PyJPProxy_clear}, { Py_tp_getset, (void*) proxyGetSets}, { Py_tp_methods, (void*) proxyMethods}, {0} }; PyTypeObject *PyJPProxy_Type = NULL; PyType_Spec PyJPProxySpec = { "_jpype._JProxy", sizeof (PyJPProxy), 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, proxySlots }; #ifdef __cplusplus } #endif void PyJPProxy_initType(PyObject* module) { JPPyObject bases = JPPyObject::call(PyTuple_Pack(1, &PyBaseObject_Type)); PyJPProxy_Type = (PyTypeObject*) PyType_FromSpecWithBases(&PyJPProxySpec, bases.get()); JP_PY_CHECK(); PyModule_AddObject(module, "_JProxy", (PyObject*) PyJPProxy_Type); JP_PY_CHECK(); } JPProxy *PyJPProxy_getJPProxy(PyObject* obj) { if (PyObject_IsInstance(obj, (PyObject*) PyJPProxy_Type)) return ((PyJPProxy*) obj)->m_Proxy; return NULL; } jpype-1.3.0/native/python/pyjp_value.cpp000066400000000000000000000213071405671516700203520ustar00rootroot00000000000000/***************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. *****************************************************************************/ #include "jpype.h" #include "pyjp.h" #include "jp_boxedtype.h" #include "jp_stringtype.h" #ifdef __cplusplus extern "C" { #endif /** * Allocate a new Python object with a slot for Java. * * We need extra space to store our values, but because there * is no way to do so without disturbing the object layout. * Fortunately, Python already handles this for dict and weakref. * Python aligns the ends of the structure and increases the * base type size to add additional slots to a standard object. * * We will use the same trick to add an additional slot for Java * after the end of the object outside of where Python is looking. * As the memory is aligned this is safe to do. We will use * the alloc and finalize slot to recognize which objects have this * extra slot appended. */ PyObject* PyJPValue_alloc(PyTypeObject* type, Py_ssize_t nitems ) { JP_PY_TRY("PyJPValue_alloc"); // Modification from Python to add size elements const size_t size = _PyObject_VAR_SIZE(type, nitems + 1) + sizeof (JPValue); PyObject *obj = (PyType_IS_GC(type)) ? _PyObject_GC_Malloc(size) : (PyObject *) PyObject_MALLOC(size); if (obj == NULL) return PyErr_NoMemory(); // GCOVR_EXCL_LINE memset(obj, 0, size); Py_ssize_t refcnt = ((PyObject*) type)->ob_refcnt; if (type->tp_itemsize == 0) PyObject_Init(obj, type); else PyObject_InitVar((PyVarObject *) obj, type, nitems); // This line is required to deal with Python bug (GH-11661) // Some versions of Python fail to increment the reference counter of // heap types properly. if (refcnt == ((PyObject*) type)->ob_refcnt) Py_INCREF(type); // GCOVR_EXCL_LINE if (PyType_IS_GC(type)) { PyObject_GC_Track(obj); } JP_TRACE("alloc", type->tp_name, obj); return obj; JP_PY_CATCH(NULL); } bool PyJPValue_hasJavaSlot(PyTypeObject* type) { if (type == NULL || type->tp_alloc != (allocfunc) PyJPValue_alloc || type->tp_finalize != (destructor) PyJPValue_finalize) return false; // GCOVR_EXCL_LINE return true; } Py_ssize_t PyJPValue_getJavaSlotOffset(PyObject* self) { PyTypeObject *type = Py_TYPE(self); if (type == NULL || type->tp_alloc != (allocfunc) PyJPValue_alloc || type->tp_finalize != (destructor) PyJPValue_finalize) return 0; Py_ssize_t offset; Py_ssize_t sz = Py_SIZE(self); // I have no clue what negative sizes mean if (sz < 0) sz = -sz; if (type->tp_itemsize == 0) offset = _PyObject_VAR_SIZE(type, 1); else offset = _PyObject_VAR_SIZE(type, sz + 1); return offset; } /** * Get the Java value if attached. * * The Java class is guaranteed not to be null on success. * * @param obj * @return the Java value or 0 if not found. */ JPValue* PyJPValue_getJavaSlot(PyObject* self) { Py_ssize_t offset = PyJPValue_getJavaSlotOffset(self); if (offset == 0) return NULL; JPValue* value = (JPValue*) (((char*) self) + offset); if (value->getClass() == NULL) return NULL; return value; } void PyJPValue_free(void* obj) { JP_PY_TRY("PyJPValue_free", obj); // Normally finalize is not run on simple classes. PyTypeObject *type = Py_TYPE(obj); if (type->tp_finalize != NULL) type->tp_finalize((PyObject*) obj); if (type->tp_flags & Py_TPFLAGS_HAVE_GC) PyObject_GC_Del(obj); else PyObject_Free(obj); // GCOVR_EXCL_LINE JP_PY_CATCH_NONE(); } void PyJPValue_finalize(void* obj) { JP_PY_TRY("PyJPValue_finalize", obj); JP_TRACE("type", Py_TYPE(obj)->tp_name); JPValue* value = PyJPValue_getJavaSlot((PyObject*) obj); if (value == NULL) return; JPContext *context = JPContext_global; if (context == NULL || !context->isRunning()) return; JPJavaFrame frame = JPJavaFrame::outer(context); JPClass* cls = value->getClass(); // This one can't check for initialized because we may need to delete a stale // resource after shutdown. if (cls != NULL && context->isRunning() && !cls->isPrimitive()) { JP_TRACE("Value", cls->getCanonicalName(), &(value->getValue())); JP_TRACE("Dereference object"); context->ReleaseGlobalRef(value->getValue().l); *value = JPValue(); } JP_PY_CATCH_NONE(); } /** This is the way to convert an object into a python string. */ PyObject* PyJPValue_str(PyObject* self) { JP_PY_TRY("PyJPValue_str", self); JPContext *context = PyJPModule_getContext(); JPJavaFrame frame = JPJavaFrame::outer(context); JPValue* value = PyJPValue_getJavaSlot(self); if (value == NULL) { PyErr_SetString(PyExc_TypeError, "Not a Java value"); return NULL; } JPClass* cls = value->getClass(); if (cls->isPrimitive()) { PyErr_SetString(PyExc_TypeError, "toString requires a Java object"); return NULL; } if (value->getValue().l == NULL) return JPPyString::fromStringUTF8("null").keep(); if (cls == context->_java_lang_String) { PyObject *cache; JPPyObject dict = JPPyObject::accept(PyObject_GenericGetDict(self, NULL)); if (!dict.isNull()) { cache = PyDict_GetItemString(dict.get(), "_jstr"); if (cache) { Py_INCREF(cache); return cache; } jstring jstr = (jstring) value->getValue().l; string str; str = frame.toStringUTF8(jstr); cache = JPPyString::fromStringUTF8(str).keep(); PyDict_SetItemString(dict.get(), "_jstr", cache); return cache; } } // In general toString is not immutable, so we won't cache it. return JPPyString::fromStringUTF8(frame.toString(value->getValue().l)).keep(); JP_PY_CATCH(NULL); } PyObject *PyJPValue_getattro(PyObject *obj, PyObject *name) { JP_PY_TRY("PyJPObject_getattro"); if (!PyUnicode_Check(name)) { PyErr_Format(PyExc_TypeError, "attribute name must be string, not '%.200s'", Py_TYPE(name)->tp_name); return NULL; } // Private members are accessed directly PyObject* pyattr = PyBaseObject_Type.tp_getattro(obj, name); if (pyattr == NULL) return NULL; JPPyObject attr = JPPyObject::accept(pyattr); // Private members go regardless if (PyUnicode_GetLength(name) && PyUnicode_ReadChar(name, 0) == '_') return attr.keep(); // Methods if (Py_TYPE(attr.get()) == (PyTypeObject*) PyJPMethod_Type) return attr.keep(); // Don't allow properties to be rewritten if (!PyObject_IsInstance(attr.get(), (PyObject*) & PyProperty_Type)) return attr.keep(); PyErr_Format(PyExc_AttributeError, "Field '%U' is static", name); return NULL; JP_PY_CATCH(NULL); } int PyJPValue_setattro(PyObject *self, PyObject *name, PyObject *value) { JP_PY_TRY("PyJPObject_setattro"); // Private members are accessed directly if (PyUnicode_GetLength(name) && PyUnicode_ReadChar(name, 0) == '_') return PyObject_GenericSetAttr(self, name, value); JPPyObject f = JPPyObject::accept(PyJP_GetAttrDescriptor(Py_TYPE(self), name)); if (f.isNull()) { PyErr_Format(PyExc_AttributeError, "Field '%U' is not found", name); return -1; } descrsetfunc desc = Py_TYPE(f.get())->tp_descr_set; if (desc != NULL) return desc(f.get(), self, value); // Not a descriptor PyErr_Format(PyExc_AttributeError, "Field '%U' is not settable on Java '%s' object", name, Py_TYPE(self)->tp_name); return -1; JP_PY_CATCH(-1); } #ifdef __cplusplus } #endif // These are from the internal methods when we already have the jvalue void PyJPValue_assignJavaSlot(JPJavaFrame &frame, PyObject* self, const JPValue& value) { Py_ssize_t offset = PyJPValue_getJavaSlotOffset(self); // GCOVR_EXCL_START if (offset == 0) { std::stringstream ss; ss << "Missing Java slot on `" << Py_TYPE(self)->tp_name << "`"; JP_RAISE(PyExc_SystemError, ss.str().c_str()); } // GCOVR_EXCL_STOP JPValue* slot = (JPValue*) (((char*) self) + offset); // GCOVR_EXCL_START // This is a sanity check that should never trigger in normal operations. if (slot->getClass() != NULL) { JP_RAISE(PyExc_SystemError, "Slot assigned twice"); } // GCOVR_EXCL_STOP JPClass* cls = value.getClass(); if (cls != NULL && !cls->isPrimitive()) { jvalue q; q.l = frame.NewGlobalRef(value.getValue().l); *slot = JPValue(cls, q); } else *slot = value; } bool PyJPValue_isSetJavaSlot(PyObject* self) { Py_ssize_t offset = PyJPValue_getJavaSlotOffset(self); if (offset == 0) return false; // GCOVR_EXCL_LINE JPValue* slot = (JPValue*) (((char*) self) + offset); return slot->getClass() != NULL; }jpype-1.3.0/project/000077500000000000000000000000001405671516700143245ustar00rootroot00000000000000jpype-1.3.0/project/README.md000066400000000000000000000002071405671516700156020ustar00rootroot00000000000000This directory contains project files for netbeans to use for editing and refactoring. These files are not used to build the project. jpype-1.3.0/project/debug/000077500000000000000000000000001405671516700154125ustar00rootroot00000000000000jpype-1.3.0/project/debug/unix/000077500000000000000000000000001405671516700163755ustar00rootroot00000000000000jpype-1.3.0/project/debug/unix/README.rst000066400000000000000000000076071405671516700200760ustar00rootroot00000000000000JVM startup debugging ===================== So the JVM won't start under JPype. It works fine for everyone else, but just not you. Now what? The following instructions are for Linux, but apply to most unix like systems with minor modifications. JAVA_HOME --------- First make sure your JAVA_HOME is set correctly. It should point to a directory containing the JRE or JDK. It should look something like...:: bin conf COPYRIGHT include jmods legal lib release For Unix we expect to find ``$JAVA_HOME\lib\server\libjvm.so`` or ``$JAVA_HOME\lib\client\libjvm.dll``. We will assume it is server for this document. Architecture ------------ To check the type of a file, use the ``file`` command. First lets check the architecture of the ``libjvm.so`` file:: $ file $JAVA_HOME/lib/server/libjvm.so /usr/lib/jvm/java-11-openjdk-amd64/lib/server/libjvm.so: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, BuildID[sha1]=1313ccf3deaef446a6c2fec9561f2232e4202bc8, stripped We can also check the architecture of python or the test file:: $ file a.out a.out: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 3.2.0, BuildID[sha1]=24c58f45e6aa4a41c0d69a74063243b692d51e0d, not stripped $ file /usr/bin/python3.8 /usr/bin/python3.8: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 3.2.0, BuildID[sha1]=f9e05e26d8232239158889727d8056c122a9e958, stripped The import thing is that each must have the samme architecture. In this case, 64-bit LSB x86-64. If one or more libraries or binaries has a mismatch then it likely won't work with that JVM. Dependencies ------------ The JVM has many dependencies. If any of them are missing, or not in a search path, or they are the wrong architecture then it will fail to load. To get a list of dependencies use:: ldd -v "$JAVA_HOME/lib/server/libjvm.so" It should produce an output similar to:: linux-vdso.so.1 (0x00007ffff3591000) libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fd55b5b0000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fd55b390000) libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fd55b000000) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fd55ac60000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd55a860000) /lib64/ld-linux-x86-64.so.2 (0x00007fd55cc00000) libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fd55a640000) If any of these libraries are missing or the wrong architecture it will cause issues. Testing the JVM --------------- Assuming that you have the JAVA_HOME set, the architectures are correct, and all of the dependencies are in place it should load. But lets run a test. Compile using the System C++ compiler. Use:: g++ testJVM.cpp -ldl Run it with:: a.out "$JAVA_HOME\lib\server\libjvm.so" It should produce and output like:: $ ./a.out $JAVA_HOME/lib/server/libjvm.so Load library Load entry points Entry point found 0x7fad8e08f670 Pack JVM arguments Num options: 0 Create JVM Create Java resources Destroy JVM Unload library Success Testing static load ------------------- Dlopen provides very little diagnostic information. So you may want to try a static JVM load. To build a static JVM test use:: g++ staticJVM.cpp -ljvm -L $JAVA_HOME/lib/server/ The launch it with:: LD_LIBRARY_PATH=$JAVA_HOME/lib/server a.out This should produce the output:: Pack JVM arguments Num options: 0 Create JVM Create Java resources Destroy JVM Success If the library does not match it should produce something like:: ./a.out: error while loading shared libraries: libjvm.so: cannot open shared object file: No such file or directory jpype-1.3.0/project/debug/unix/staticJVM.cpp000066400000000000000000000032301405671516700207430ustar00rootroot00000000000000#if defined(_HPUX) && !defined(_IA64) #include #else #include #endif // HPUX #include #include #include #include #include //#include #include "../../../native/jni_include/jni.h" #define USE_JNI_VERSION JNI_VERSION_1_4 JavaVM *jvm; int main(int argc, char** argv) { if (argc < 1) { printf("Usage: %s [JVM_ARGS]\n", argv[0]); exit(-1); } // Pack the arguments printf("Pack JVM arguments\n"); JavaVMInitArgs jniArgs; jniArgs.options = NULL; jniArgs.version = USE_JNI_VERSION; jniArgs.ignoreUnrecognized = false; jniArgs.nOptions = (jint) argc - 1; printf(" Num options: %d\n", jniArgs.nOptions); jniArgs.options = (JavaVMOption*) malloc(sizeof (JavaVMOption) * jniArgs.nOptions); memset(jniArgs.options, 0, sizeof (JavaVMOption) * jniArgs.nOptions); for (int i = 0; i < jniArgs.nOptions; i++) { printf(" Option %s\n", argv[i + 1]); jniArgs.options[i].optionString = (char*) argv[i + 1]; } // Launch the JVM printf("Create JVM\n"); JNIEnv* env; jint rc = JNI_CreateJavaVM(&jvm, (JNIEnv**) &env, (void*) &jniArgs); free(jniArgs.options); if (rc != JNI_OK) { printf(" Create JVM failed. (%d)\n", rc); exit(-1); } // Create some resources printf("Create Java resources\n"); jclass cls = env->FindClass("java/lang/Object"); jmethodID mth = env->GetMethodID(cls, "toString", "()Ljava/lang/String;"); mth = env->GetMethodID(cls, "equals", "(Ljava/lang/Object;)Z"); mth = env->GetMethodID(cls, "hashCode", "()I"); mth = env->GetMethodID(cls, "getClass", "()Ljava/lang/Class;"); // Destroy the JVM printf("Destroy JVM\n"); jvm->DestroyJavaVM(); printf("Success\n"); } jpype-1.3.0/project/debug/unix/testJVM.cpp000066400000000000000000000056221405671516700204420ustar00rootroot00000000000000#if defined(_HPUX) && !defined(_IA64) #include #else #include #endif // HPUX #include #include #include #include #include //#include #include "../../../native/jni_include/jni.h" void* jvmLibrary; jint(JNICALL * CreateJVM_Method)(JavaVM **pvm, void **penv, void *args); #define USE_JNI_VERSION JNI_VERSION_1_4 JavaVM *jvm; void loadLibrary(const char* path) { #if defined(_HPUX) && !defined(_IA64) jvmLibrary = shl_load(path, BIND_DEFERRED | BIND_VERBOSE, 0L); #else jvmLibrary = dlopen(path, RTLD_LAZY | RTLD_GLOBAL); #endif // HPUX if (jvmLibrary == NULL) { printf("Failed to load JVM from %s\n", path); printf("Errno: %d\n", errno); if (errno == ENOEXEC) { printf("diagnostics: %s\n", dlerror()); } exit(-1); } } void unloadLibrary() { int r = dlclose(jvmLibrary); if (r != 0) // error { printf(" Failed to unload JVM\n"); printf("Errno: %d\n", errno); printf("Dlerror: %s\n", dlerror()); exit(-1); } } void* getSymbol(const char* name) { void* res = dlsym(jvmLibrary, name); if (res == NULL) { printf(" Failed to get Symbol %s\n", name); printf("errno %d\n", errno); exit(-1); } return res; } void loadEntryPoints() { CreateJVM_Method = (jint(JNICALL *)(JavaVM **, void **, void *) )getSymbol("JNI_CreateJavaVM"); printf(" Entry point found %p\n", CreateJVM_Method); } int main(int argc, char** argv) { if (argc < 2) { printf("Usage: %s $JAVA_HOME/lib/server/libjvm.so [JVM_ARGS]\n", argv[0]); exit(-1); } printf("Load library\n"); loadLibrary(argv[1]); printf("Load entry points\n"); loadEntryPoints(); // Pack the arguments printf("Pack JVM arguments\n"); JavaVMInitArgs jniArgs; jniArgs.options = NULL; jniArgs.version = USE_JNI_VERSION; jniArgs.ignoreUnrecognized = false; jniArgs.nOptions = (jint) argc - 2; printf(" Num options: %d\n", jniArgs.nOptions); jniArgs.options = (JavaVMOption*) malloc(sizeof (JavaVMOption) * jniArgs.nOptions); memset(jniArgs.options, 0, sizeof (JavaVMOption) * jniArgs.nOptions); for (int i = 0; i < jniArgs.nOptions; i++) { printf(" Option %s\n", argv[i + 2]); jniArgs.options[i].optionString = (char*) argv[i + 2]; } // Launch the JVM printf("Create JVM\n"); JNIEnv* env; jint rc = CreateJVM_Method(&jvm, (void**) &env, (void*) &jniArgs); free(jniArgs.options); if (rc != JNI_OK) { printf(" Create JVM failed. (%d)\n", rc); exit(-1); } // Create some resources printf("Create Java resources\n"); jclass cls = env->FindClass("java/lang/Object"); jmethodID mth = env->GetMethodID(cls, "toString", "()Ljava/lang/String;"); mth = env->GetMethodID(cls, "equals", "(Ljava/lang/Object;)Z"); mth = env->GetMethodID(cls, "hashCode", "()I"); mth = env->GetMethodID(cls, "getClass", "()Ljava/lang/Class;"); // Destroy the JVM printf("Destroy JVM\n"); jvm->DestroyJavaVM(); printf("Unload library\n"); unloadLibrary(); printf("Success\n"); } jpype-1.3.0/project/debug/windows/000077500000000000000000000000001405671516700171045ustar00rootroot00000000000000jpype-1.3.0/project/debug/windows/README.rst000066400000000000000000000124551405671516700206020ustar00rootroot00000000000000JVM startup debugging ===================== So the JVM won't start under JPype. It works fine for everyone else, but just not you. Now what? JAVA_HOME --------- First make sure your JAVA_HOME is set correctly. It should point to a directory containing the JRE or JDK. It should look something like...:: bin conf COPYRIGHT include jmods legal lib release For Windows we expect to find ``%JAVA_HOME%\bin\server\jvm.dll`` or ``%JAVA_HOME%\bin\client\jvm.dll``. We will assume it is server for this document. Architecture ------------ Next make sure that Python and the JVM have the same architecture. We can do this with ``DUMPBIN``. Run:: dumpbin /headers "%JAVA_HOME%/bin/jvm.dll" It will produce a big output. The relevant section is:: File Type: DLL FILE HEADER VALUES 8664 machine (x64) <== Type is x64 7 number of sections 5CA35D83 time date stamp Tue Apr 2 06:02:59 2019 0 file pointer to symbol table 0 number of symbols F0 size of optional header 2022 characteristics Executable Application can handle large (>2GB) addresses DLL Run the same command on the Python executable:: File Type: EXECUTABLE IMAGE FILE HEADER VALUES 8664 machine (x64) <== Type is x64 6 number of sections 5C9BF5B3 time date stamp Wed Mar 27 15:14:11 2019 0 file pointer to symbol table 0 number of symbols F0 size of optional header 22 characteristics Executable Application can handle large (>2GB) addresses If they match then the issue is not an architecture problem. Dependencies ------------ The JVM has many dependencies. If any of them are missing, or not in a search path, or they are the wrong architecture then it will fail to load. To get a list of dependencies use:: dumpbin /dependents "%JAVA_HOME%/bin/server/jvm.dll" It should produce an output:: Dump of file C:\Program Files\Java\jdk-12.0.1/bin/server/jvm.dll File Type: DLL Image has the following dependencies: KERNEL32.dll USER32.dll ADVAPI32.dll WSOCK32.dll WINMM.dll VERSION.dll PSAPI.DLL VCRUNTIME140.dll api-ms-win-crt-stdio-l1-1-0.dll api-ms-win-crt-string-l1-1-0.dll api-ms-win-crt-runtime-l1-1-0.dll api-ms-win-crt-convert-l1-1-0.dll api-ms-win-crt-environment-l1-1-0.dll api-ms-win-crt-utility-l1-1-0.dll api-ms-win-crt-math-l1-1-0.dll api-ms-win-crt-filesystem-l1-1-0.dll api-ms-win-crt-time-l1-1-0.dll api-ms-win-crt-heap-l1-1-0.dll Summary DB000 .data 59000 .pdata 243000 .rdata 39000 .reloc 1000 .rsrc 7BF000 .text 3000 _RDATA So every one of these libraries needs to be found on the path. All of the required DLLs should be located in ``%JAVA_HOME%/bin``. However, Windows search order may find another copy of one of these DLLs elsewhere in the search process. If the file it finds is the wrong architechure or corrupt the JVM will fail to load. Please note the search order in https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-search-order The order is:: 1) The directory from which the application loaded. 2) The current directory. 3) The system directory. Use the GetSystemDirectory function to get the path of this directory. 4) The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched. 5) The Windows directory. Use the GetWindowsDirectory function to get the path of this directory. 6) The directories that are listed in the PATH environment variable. Note that this does not include the per-application path specified by the App Paths registry key. The App Paths key is not used when computing the DLL search path. So even if the PATH is pointing to ``%JAVA_HOME%/bin``, you may have a bad dll in any of the first 5 places. Testing the JVM --------------- Assuming that you have the JAVA_HOME set, the architectures are correct, and all of the dependencies are in place it should load. But lets run a test. Compile using the Visual Studio shell ``x64 Native Tools Command`` or ``x86 Native Tools Command`` depending on your Python architecture. Use:: CL.EXE testJVM.cpp Run it with:: testJVM.exe "%JAVA_HOME%\bin\server\jvm.dll" It should produce and output like:: Check paths SystemDirectory: C:\windows\system32 WindowsDirectory: C:\windows Load library Load entry points Entry point found 00007FFEDE4703B0 Pack JVM arguments Num options: 0 Create JVM Create Java resources Destroy JVM Unload library Success Here are some common problems: The architecture of the jvm or one of the dependencies does not match the program or is corrupted:: Failed to load JVM from C:\Program Files (x86)\Java\jre1.8.0_251\bin\client\jvm.dll LastError 193 Message: %1 is not a valid Win32 application. A module or jar file is missing from the Java distribution:: Failed to load JVM from jvm1.dll Error occurred during initialization of VM Failed setting boot class path. A dll used by the JVM is missing:: Failed to load JVM from jvm1.dll LastError 126 Message: The specified module could not be found. jpype-1.3.0/project/debug/windows/testJVM.cpp000066400000000000000000000071361405671516700211530ustar00rootroot00000000000000#include #include //#include #include "../../../native/jni_include/jni.h" HINSTANCE jvmLibrary; jint(JNICALL * CreateJVM_Method)(JavaVM **pvm, void **penv, void *args); #define USE_JNI_VERSION JNI_VERSION_1_4 JavaVM *jvm; std::string formatMessage(DWORD msgCode) { LPVOID lpMsgBuf; DWORD rc = ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, msgCode, 0, (LPTSTR) & lpMsgBuf, 0, NULL ); if (rc == 0) { printf("format message returned 0 (%d)", ::GetLastError()); exit(-1); } std::string res((LPTSTR) lpMsgBuf); ::LocalFree(lpMsgBuf); return res; } void loadLibrary(const char* path) { jvmLibrary = ::LoadLibrary(path); if (jvmLibrary == NULL) { printf("Failed to load JVM from %s\n", path); printf("LastError %d\n", GetLastError()); printf("Message: %s\n", formatMessage(GetLastError()).c_str()); exit(-1); } } void unloadLibrary() { if (::FreeLibrary(jvmLibrary) == 0) { printf(" Failed to unload JVM\n"); printf(" LastError %d\n", GetLastError()); printf(" Message: %s\n", formatMessage(GetLastError()).c_str()); exit(-1); } } void* getSymbol(const char* name) { void* res = (void*) ::GetProcAddress(jvmLibrary, name); if (res == NULL) { printf(" Failed to get Symbol %s\n", name); printf(" LastError %d\n", GetLastError()); printf(" Message: %s\n", formatMessage(GetLastError()).c_str()); exit(-1); } return res; } void loadEntryPoints() { CreateJVM_Method = (jint(JNICALL *)(JavaVM **, void **, void *) )getSymbol("JNI_CreateJavaVM"); printf(" Entry point found %p\n", CreateJVM_Method); } int main(int argc, char** argv) { if (argc < 2) { printf("Usage: %s %%JAVA_HOME%%/bin/server/jvm.dll [JVM_ARGS]", argv[0]); exit(-1); } printf("Check paths\n"); char directory[1024]; int sz = ::GetSystemDirectoryA(directory, 1024); if (sz == 0) { printf("GetSystemDirectory failed\n"); exit(-1); } printf(" SystemDirectory: %s\n", std::string(directory, sz).c_str()); sz = ::GetWindowsDirectoryA(directory, 1024); if (sz == 0) { printf("GetWindowsDirectory failed\n"); exit(-1); } printf(" WindowsDirectory: %s\n", std::string(directory, sz).c_str()); printf("Load library\n"); loadLibrary(argv[1]); printf("Load entry points\n"); loadEntryPoints(); // Pack the arguments printf("Pack JVM arguments\n"); JavaVMInitArgs jniArgs; jniArgs.options = NULL; jniArgs.version = USE_JNI_VERSION; jniArgs.ignoreUnrecognized = false; jniArgs.nOptions = (jint) argc - 2; printf(" Num options: %d\n", jniArgs.nOptions); jniArgs.options = (JavaVMOption*) malloc(sizeof (JavaVMOption) * jniArgs.nOptions); memset(jniArgs.options, 0, sizeof (JavaVMOption) * jniArgs.nOptions); for (int i = 0; i < jniArgs.nOptions; i++) { printf(" Option %s\n", argv[i + 2]); jniArgs.options[i].optionString = (char*) argv[i + 2]; } // Launch the JVM printf("Create JVM\n"); JNIEnv* env; jint rc = CreateJVM_Method(&jvm, (void**) &env, (void*) &jniArgs); free(jniArgs.options); if (rc != JNI_OK) { printf(" Create JVM failed. (%d)\n", rc); exit(-1); } // Create some resources printf("Create Java resources\n"); jclass cls = env->FindClass("java/lang/Object"); jmethodID mth = env->GetMethodID(cls, "toString", "()Ljava/lang/String;"); mth = env->GetMethodID(cls, "equals", "(Ljava/lang/Object;)Z"); mth = env->GetMethodID(cls, "hashCode", "()I"); mth = env->GetMethodID(cls, "getClass", "()Ljava/lang/Class;"); // Destroy the JVM printf("Destroy JVM\n"); jvm->DestroyJavaVM(); printf("Unload library\n"); unloadLibrary(); printf("Success\n"); } jpype-1.3.0/project/jars/000077500000000000000000000000001405671516700152635ustar00rootroot00000000000000jpype-1.3.0/project/jars/README000066400000000000000000000001251405671516700161410ustar00rootroot00000000000000This directory contains patterns for constructing special jar files used in testing. jpype-1.3.0/project/jars/late/000077500000000000000000000000001405671516700162105ustar00rootroot00000000000000jpype-1.3.0/project/jars/late/build.sh000066400000000000000000000003121405671516700176370ustar00rootroot00000000000000javac --release 7 -d classes1 src/org/jpype/late/*.java javac --release 7 -d classes2 src/org/jpype/late2/*.java jar --create --file late.jar -C classes1 . jar --create --file late2.jar -C classes2 . jpype-1.3.0/project/jars/late/src/000077500000000000000000000000001405671516700167775ustar00rootroot00000000000000jpype-1.3.0/project/jars/late/src/org/000077500000000000000000000000001405671516700175665ustar00rootroot00000000000000jpype-1.3.0/project/jars/late/src/org/jpype/000077500000000000000000000000001405671516700207155ustar00rootroot00000000000000jpype-1.3.0/project/jars/late/src/org/jpype/late/000077500000000000000000000000001405671516700216425ustar00rootroot00000000000000jpype-1.3.0/project/jars/late/src/org/jpype/late/Test.java000066400000000000000000000001651405671516700234260ustar00rootroot00000000000000package org.jpype.late; public class Test { public int field = 5; public String method() { return "Yes"; } } jpype-1.3.0/project/jars/late/src/org/jpype/late2/000077500000000000000000000000001405671516700217245ustar00rootroot00000000000000jpype-1.3.0/project/jars/late/src/org/jpype/late2/Test.java000066400000000000000000000001651405671516700235100ustar00rootroot00000000000000package org.jpype.late2; public class Test { public int field = 6; public String method() { return "No"; } } jpype-1.3.0/project/jars/missing/000077500000000000000000000000001405671516700167345ustar00rootroot00000000000000jpype-1.3.0/project/jars/missing/build.sh000066400000000000000000000002451405671516700203700ustar00rootroot00000000000000javac --release 7 -d classes src/org/jpype/missing/*.java jar --create --file missing.jar -M -C classes META-INF/MANIFEST.MF -C classes org/jpype/missing/Test.class jpype-1.3.0/project/jars/missing/classes/000077500000000000000000000000001405671516700203715ustar00rootroot00000000000000jpype-1.3.0/project/jars/missing/classes/META-INF/000077500000000000000000000000001405671516700215315ustar00rootroot00000000000000jpype-1.3.0/project/jars/missing/classes/META-INF/MANIFEST.MF000066400000000000000000000000701405671516700231600ustar00rootroot00000000000000Manifest-Version: 1.0 Created-By: 11.0.9.1 (Ubuntu) jpype-1.3.0/project/jars/missing/src/000077500000000000000000000000001405671516700175235ustar00rootroot00000000000000jpype-1.3.0/project/jars/missing/src/org/000077500000000000000000000000001405671516700203125ustar00rootroot00000000000000jpype-1.3.0/project/jars/missing/src/org/jpype/000077500000000000000000000000001405671516700214415ustar00rootroot00000000000000jpype-1.3.0/project/jars/missing/src/org/jpype/missing/000077500000000000000000000000001405671516700231125ustar00rootroot00000000000000jpype-1.3.0/project/jars/missing/src/org/jpype/missing/Test.java000066400000000000000000000000631405671516700246730ustar00rootroot00000000000000package org.jpype.missing; public class Test { } jpype-1.3.0/project/jars/mrjar/000077500000000000000000000000001405671516700163765ustar00rootroot00000000000000jpype-1.3.0/project/jars/mrjar/README000066400000000000000000000000751405671516700172600ustar00rootroot00000000000000This is the sources for building the multi-release jar test. jpype-1.3.0/project/jars/mrjar/build.sh000066400000000000000000000003721405671516700200330ustar00rootroot00000000000000javac --release 7 -d classes src/org/jpype/mrjar/*.java javac --release 7 -d classes src/org/jpype/mrjar/sub/*.java javac --release 9 -d classes-9 src/java9/org/jpype/mrjar/*.java jar --create --file mrjar.jar -C classes . --release 9 -C classes-9 . jpype-1.3.0/project/jars/mrjar/src/000077500000000000000000000000001405671516700171655ustar00rootroot00000000000000jpype-1.3.0/project/jars/mrjar/src/java9/000077500000000000000000000000001405671516700201775ustar00rootroot00000000000000jpype-1.3.0/project/jars/mrjar/src/java9/org/000077500000000000000000000000001405671516700207665ustar00rootroot00000000000000jpype-1.3.0/project/jars/mrjar/src/java9/org/jpype/000077500000000000000000000000001405671516700221155ustar00rootroot00000000000000jpype-1.3.0/project/jars/mrjar/src/java9/org/jpype/mrjar/000077500000000000000000000000001405671516700232305ustar00rootroot00000000000000jpype-1.3.0/project/jars/mrjar/src/java9/org/jpype/mrjar/B.java000066400000000000000000000001271405671516700242540ustar00rootroot00000000000000package org.jpype.mrjar; public class B { public String call() { return "9"; } } jpype-1.3.0/project/jars/mrjar/src/org/000077500000000000000000000000001405671516700177545ustar00rootroot00000000000000jpype-1.3.0/project/jars/mrjar/src/org/jpype/000077500000000000000000000000001405671516700211035ustar00rootroot00000000000000jpype-1.3.0/project/jars/mrjar/src/org/jpype/mrjar/000077500000000000000000000000001405671516700222165ustar00rootroot00000000000000jpype-1.3.0/project/jars/mrjar/src/org/jpype/mrjar/A.java000066400000000000000000000000551405671516700232410ustar00rootroot00000000000000package org.jpype.mrjar; public class A { } jpype-1.3.0/project/jars/mrjar/src/org/jpype/mrjar/B.java000066400000000000000000000001271405671516700232420ustar00rootroot00000000000000package org.jpype.mrjar; public class B { public String call() { return "7"; } } jpype-1.3.0/project/jars/mrjar/src/org/jpype/mrjar/sub/000077500000000000000000000000001405671516700230075ustar00rootroot00000000000000jpype-1.3.0/project/jars/mrjar/src/org/jpype/mrjar/sub/C.java000066400000000000000000000000611405671516700240310ustar00rootroot00000000000000package org.jpype.mrjar.sub; public class C { } jpype-1.3.0/project/jars/unsatisfied/000077500000000000000000000000001405671516700176015ustar00rootroot00000000000000jpype-1.3.0/project/jars/unsatisfied/build.sh000066400000000000000000000002501405671516700212310ustar00rootroot00000000000000javac --release 7 -d classes src/org/jpype/unsatisfied/*.java rm classes/org/jpype/unsatisfied/UnsatisfiedClass.class jar --create --file unsatisfied.jar -C classes . jpype-1.3.0/project/jars/unsatisfied/src/000077500000000000000000000000001405671516700203705ustar00rootroot00000000000000jpype-1.3.0/project/jars/unsatisfied/src/org/000077500000000000000000000000001405671516700211575ustar00rootroot00000000000000jpype-1.3.0/project/jars/unsatisfied/src/org/jpype/000077500000000000000000000000001405671516700223065ustar00rootroot00000000000000jpype-1.3.0/project/jars/unsatisfied/src/org/jpype/unsatisfied/000077500000000000000000000000001405671516700246245ustar00rootroot00000000000000jpype-1.3.0/project/jars/unsatisfied/src/org/jpype/unsatisfied/TestClass.java000066400000000000000000000004131405671516700273720ustar00rootroot00000000000000package org.jpype.unsatisfied; public class TestClass { public static void main(String[] args) { System.out.println("Hi Freaks"); } public static UnsatisfiedClass methodWithUnsatisfiedReturnType() { return null; } } class UnsatisfiedClass { } jpype-1.3.0/project/jpype_cpython/000077500000000000000000000000001405671516700172175ustar00rootroot00000000000000jpype-1.3.0/project/jpype_cpython/nbproject/000077500000000000000000000000001405671516700212055ustar00rootroot00000000000000jpype-1.3.0/project/jpype_cpython/nbproject/configurations.xml000077500000000000000000001232131405671516700247660ustar00rootroot00000000000000 ../../native/common/include/jp_array.h ../../native/common/include/jp_arrayclass.h ../../native/common/include/jp_booleantype.h ../../native/common/include/jp_boxedtype.h ../../native/common/include/jp_buffer.h ../../native/common/include/jp_buffertype.h ../../native/common/include/jp_bytetype.h ../../native/common/include/jp_chartype.h ../../native/common/include/jp_class.h ../../native/common/include/jp_classhints.h ../../native/common/include/jp_classloader.h ../../native/common/include/jp_classtype.h ../../native/common/include/jp_context.h ../../native/common/include/jp_doubletype.h ../../native/common/include/jp_encoding.h ../../native/common/include/jp_exception.h ../../native/common/include/jp_field.h ../../native/common/include/jp_floattype.h ../../native/common/include/jp_functional.h ../../native/common/include/jp_gc.h ../../native/common/include/jp_inttype.h ../../native/common/include/jp_javaframe.h ../../native/common/include/jp_longtype.h ../../native/common/include/jp_match.h ../../native/common/include/jp_method.h ../../native/common/include/jp_methoddispatch.h ../../native/common/include/jp_modifier.h ../../native/common/include/jp_monitor.h ../../native/common/include/jp_numbertype.h ../../native/common/include/jp_objecttype.h ../../native/common/include/jp_platform.h ../../native/common/include/jp_primitive_accessor.h ../../native/common/include/jp_primitivetype.h ../../native/common/include/jp_proxy.h ../../native/common/include/jp_reference_queue.h ../../native/common/include/jp_shorttype.h ../../native/common/include/jp_stringtype.h ../../native/common/include/jp_tracer.h ../../native/common/include/jp_typemanager.h ../../native/common/include/jp_value.h ../../native/common/include/jp_voidtype.h ../../native/common/include/jpype.h ../../native/python/include/jp_pythontypes.h ../../native/python/include/pyjp.h ../../jpype/__init__.py ../../jpype/_classpath.py ../../jpype/_core.py ../../jpype/_gui.py ../../jpype/_jarray.py ../../jpype/_jclass.py ../../jpype/_jcollection.py ../../jpype/_jcustomizer.py ../../jpype/_jexception.py ../../jpype/_jinit.py ../../jpype/_jio.py ../../jpype/_jmethod.py ../../jpype/_jobject.py ../../jpype/_jpackage.py ../../jpype/_jproxy.py ../../jpype/_jstring.py ../../jpype/_jthread.py ../../jpype/_jvmfinder.py ../../jpype/_pykeywords.py ../../jpype/beans.py ../../jpype/imports.py ../../jpype/nio.py ../../jpype/pickle.py ../../jpype/protocol.py ../../jpype/types.py ../../test/jpypetest/common.py ../../test/jpypetest/conftest.py ../../test/jpypetest/subrun.py ../../test/jpypetest/test_array.py ../../test/jpypetest/test_attr.py ../../test/jpypetest/test_boxed.py ../../test/jpypetest/test_buffer.py ../../test/jpypetest/test_bytebuffer.py ../../test/jpypetest/test_caller_sensitive.py ../../test/jpypetest/test_charSequence.py ../../test/jpypetest/test_classhints.py ../../test/jpypetest/test_closeable.py ../../test/jpypetest/test_closed.py ../../test/jpypetest/test_collection.py ../../test/jpypetest/test_comparable.py ../../test/jpypetest/test_conversion.py ../../test/jpypetest/test_conversionInt.py ../../test/jpypetest/test_conversionLong.py ../../test/jpypetest/test_conversionShort.py ../../test/jpypetest/test_core.py ../../test/jpypetest/test_coverage.py ../../test/jpypetest/test_customizer.py ../../test/jpypetest/test_directbuffer.py ../../test/jpypetest/test_docstring.py ../../test/jpypetest/test_exc.py ../../test/jpypetest/test_fault.py ../../test/jpypetest/test_fields.py ../../test/jpypetest/test_forname.py ../../test/jpypetest/test_generic.py ../../test/jpypetest/test_hash.py ../../test/jpypetest/test_hints.py ../../test/jpypetest/test_imports.py ../../test/jpypetest/test_inherit.py ../../test/jpypetest/test_javacoverage.py ../../test/jpypetest/test_javadoc.py ../../test/jpypetest/test_jboolean.py ../../test/jpypetest/test_jbyte.py ../../test/jpypetest/test_jchar.py ../../test/jpypetest/test_jclass.py ../../test/jpypetest/test_jdouble.py ../../test/jpypetest/test_jedi.py ../../test/jpypetest/test_jfloat.py ../../test/jpypetest/test_jint.py ../../test/jpypetest/test_jlong.py ../../test/jpypetest/test_jmethod.py ../../test/jpypetest/test_jobject.py ../../test/jpypetest/test_jpackage.py ../../test/jpypetest/test_jshort.py ../../test/jpypetest/test_jstring.py ../../test/jpypetest/test_jvmfinder.py ../../test/jpypetest/test_keywords.py ../../test/jpypetest/test_lambdas.py ../../test/jpypetest/test_leak.py ../../test/jpypetest/test_leak2.py ../../test/jpypetest/test_legacy.py ../../test/jpypetest/test_list.py ../../test/jpypetest/test_map.py ../../test/jpypetest/test_module.py ../../test/jpypetest/test_module2.py ../../test/jpypetest/test_mro.py ../../test/jpypetest/test_number.py ../../test/jpypetest/test_numeric.py ../../test/jpypetest/test_objectwrapper.py ../../test/jpypetest/test_opts.py ../../test/jpypetest/test_overloads.py ../../test/jpypetest/test_pickle.py ../../test/jpypetest/test_properties.py ../../test/jpypetest/test_proxy.py ../../test/jpypetest/test_proxy_multithreaded.py ../../test/jpypetest/test_ref.py ../../test/jpypetest/test_reflect.py ../../test/jpypetest/test_repr.py ../../test/jpypetest/test_serial.py ../../test/jpypetest/test_shutdown.py ../../test/jpypetest/test_startup.py ../../test/jpypetest/test_synchronized.py ../../test/jpypetest/test_thread.py ../../test/jpypetest/test_utf8.py ../../test/jpypetest/test_varargs.py ../../test/jpypetest/test_virtual.py ../../test/jpypetest/test_zzz.py ../../native/common/jp_array.cpp ../../native/common/jp_arrayclass.cpp ../../native/common/jp_booleantype.cpp ../../native/common/jp_boxedtype.cpp ../../native/common/jp_buffer.cpp ../../native/common/jp_buffertype.cpp ../../native/common/jp_bytetype.cpp ../../native/common/jp_chartype.cpp ../../native/common/jp_class.cpp ../../native/common/jp_classhints.cpp ../../native/common/jp_classloader.cpp ../../native/common/jp_classtype.cpp ../../native/common/jp_context.cpp ../../native/common/jp_convert.cpp ../../native/common/jp_doubletype.cpp ../../native/common/jp_encoding.cpp ../../native/common/jp_exception.cpp ../../native/common/jp_field.cpp ../../native/common/jp_floattype.cpp ../../native/common/jp_functional.cpp ../../native/common/jp_gc.cpp ../../native/common/jp_inttype.cpp ../../native/common/jp_javaframe.cpp ../../native/common/jp_longtype.cpp ../../native/common/jp_method.cpp ../../native/common/jp_methoddispatch.cpp ../../native/common/jp_monitor.cpp ../../native/common/jp_numbertype.cpp ../../native/common/jp_objecttype.cpp ../../native/common/jp_platform.cpp ../../native/common/jp_primitivetype.cpp ../../native/common/jp_proxy.cpp ../../native/common/jp_reference_queue.cpp ../../native/common/jp_shorttype.cpp ../../native/common/jp_stringtype.cpp ../../native/common/jp_tracer.cpp ../../native/common/jp_typefactory.cpp ../../native/common/jp_typemanager.cpp ../../native/common/jp_value.cpp ../../native/common/jp_voidtype.cpp ../../native/python/jp_pythontypes.cpp ../../native/python/pyjp_array.cpp ../../native/python/pyjp_buffer.cpp ../../native/python/pyjp_char.cpp ../../native/python/pyjp_class.cpp ../../native/python/pyjp_classhints.cpp ../../native/python/pyjp_field.cpp ../../native/python/pyjp_method.cpp ../../native/python/pyjp_module.cpp ../../native/python/pyjp_monitor.cpp ../../native/python/pyjp_number.cpp ../../native/python/pyjp_object.cpp ../../native/python/pyjp_package.cpp ../../native/python/pyjp_proxy.cpp ../../native/python/pyjp_value.cpp ../../native/common ../../native/python ../../jpype ../../test/jpypetest Makefile default true false 5 5 ../../native/jni_include ../../native/python/include ../../native/common/include 5 5 ../../native/python/include ../../native/common/include jpype-1.3.0/project/jpype_cpython/nbproject/license.txt000066400000000000000000000014551405671516700233750ustar00rootroot00000000000000<#if licenseFirst??> ${licenseFirst}**************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. <#if licenseLast??> ****************************************************************************${licenseLast} jpype-1.3.0/project/jpype_cpython/nbproject/project.properties000077500000000000000000000001461405671516700247750ustar00rootroot00000000000000#Fri Jun 19 07:55:24 PDT 2020 project.license=apache20 project.licensePath=./nbproject/license.txt jpype-1.3.0/project/jpype_cpython/nbproject/project.xml000077500000000000000000000024561405671516700234070ustar00rootroot00000000000000 org.netbeans.modules.cnd.makeproject jpype_cpython cpp h UTF-8 ../../native/common ../../native/python ../../jpype ../../test/jpypetest Release 3 true ANSI|ANSI Default_0|JPype Default_1|JPype jpype-1.3.0/project/jpype_java/000077500000000000000000000000001405671516700164545ustar00rootroot00000000000000jpype-1.3.0/project/jpype_java/build.xml000077500000000000000000000005711405671516700203030ustar00rootroot00000000000000 Builds, tests, and runs the project jpype_java. jpype-1.3.0/project/jpype_java/nbproject/000077500000000000000000000000001405671516700204425ustar00rootroot00000000000000jpype-1.3.0/project/jpype_java/nbproject/license.txt000066400000000000000000000014551405671516700226320ustar00rootroot00000000000000<#if licenseFirst??> ${licenseFirst}**************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. <#if licenseLast??> ****************************************************************************${licenseLast} jpype-1.3.0/project/jpype_java/nbproject/project.properties000077500000000000000000000116431405671516700242360ustar00rootroot00000000000000annotation.processing.enabled=true annotation.processing.enabled.in.editor=false annotation.processing.processors.list= annotation.processing.run.all.processors=true annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output application.title=jpype_java application.vendor= auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.expand-tabs=true auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.indent-shift-width=4 auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.spaces-per-tab=4 auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.tab-size=8 auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width=80 auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.text-line-wrap=none auxiliary.org-netbeans-modules-editor-indent.CodeStyle.usedProfile=project auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement=NEW_LINE auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.enable-indent=true auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.expand-tabs=true auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.indent-shift-width=2 auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement=NEW_LINE auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.moduleDeclBracePlacement=NEW_LINE auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement=NEW_LINE auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.redundantForBraces=LEAVE_ALONE auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.redundantIfBraces=LEAVE_ALONE auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.redundantWhileBraces=LEAVE_ALONE auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaces-per-tab=2 auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.tab-size=8 auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.text-limit-width=80 auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.text-line-wrap=none build.classes.dir=${build.dir}/classes build.classes.excludes=**/*.java,**/*.form # This directory is removed when the project is cleaned: build.dir=build build.generated.dir=${build.dir}/generated build.generated.sources.dir=${build.dir}/generated-sources # Only compile against the classpath explicitly listed here: build.sysclasspath=ignore build.test.classes.dir=${build.dir}/test/classes build.test.results.dir=${build.dir}/test/results # Uncomment to specify the preferred debugger connection transport: #debug.transport=dt_socket debug.classpath=\ ${run.classpath} debug.modulepath=\ ${run.modulepath} debug.test.classpath=\ ${run.test.classpath} debug.test.modulepath=\ ${run.test.modulepath} # Files in build.classes.dir which should be excluded from distribution jar dist.archive.excludes= # This directory is removed when the project is cleaned: dist.dir=dist dist.jar=${dist.dir}/org.jpype.jar dist.javadoc.dir=${dist.dir}/javadoc endorsed.classpath= excludes= file.reference.native-java=../../native/java file.reference.test-harness=../../test/harness includes=** jar.compress=false javac.classpath= # Space-separated list of extra javac options javac.compilerargs= javac.deprecation=false javac.external.vm=true javac.modulepath= javac.processormodulepath= javac.processorpath=\ ${javac.classpath} javac.source=1.8 javac.target=1.8 javac.test.classpath=\ ${javac.classpath}:\ ${build.classes.dir}:\ ${libs.testng.classpath} javac.test.modulepath=\ ${javac.modulepath} javac.test.processorpath=\ ${javac.test.classpath} javadoc.additionalparam= javadoc.author=false javadoc.encoding=${source.encoding} javadoc.html5=false javadoc.noindex=false javadoc.nonavbar=false javadoc.notree=false javadoc.private=false javadoc.splitindex=true javadoc.use=true javadoc.version=false javadoc.windowtitle= jlink.launcher=false jlink.launcher.name=jpype_java meta.inf.dir=${src.dir}/META-INF mkdist.disabled=true platform.active=default_platform project.licensePath=./nbproject/license.txt run.classpath=\ ${javac.classpath}:\ ${build.classes.dir} # Space-separated list of JVM arguments used when running the project. # You may also define separate properties like run-sys-prop.name=value instead of -Dname=value. # To set system properties for unit tests define test-sys-prop.name=value: run.jvmargs= run.modulepath=\ ${javac.modulepath} run.test.classpath=\ ${javac.test.classpath}:\ ${build.test.classes.dir} run.test.modulepath=\ ${javac.test.modulepath} source.encoding=UTF-8 src.java.dir=${file.reference.native-java} test.harness.dir=${file.reference.test-harness} test.src.dir=test jpype-1.3.0/project/jpype_java/nbproject/project.xml000077500000000000000000000011311405671516700226310ustar00rootroot00000000000000 org.netbeans.modules.java.j2seproject jpype_java jpype-1.3.0/project/jpype_java/test/000077500000000000000000000000001405671516700174335ustar00rootroot00000000000000jpype-1.3.0/project/jpype_java/test/org/000077500000000000000000000000001405671516700202225ustar00rootroot00000000000000jpype-1.3.0/project/jpype_java/test/org/jpype/000077500000000000000000000000001405671516700213515ustar00rootroot00000000000000jpype-1.3.0/project/jpype_java/test/org/jpype/manager/000077500000000000000000000000001405671516700227635ustar00rootroot00000000000000jpype-1.3.0/project/jpype_java/test/org/jpype/manager/TestDefault.java000066400000000000000000000036441405671516700260610ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype.manager; import java.lang.reflect.Method; import java.util.EnumSet; /** * * @author nelson85 */ public class TestDefault { public interface Foo { default void fred() { } void george(); static void bob() { } } static public void main(String[] args) { System.out.println("declared:"); for (Method method : int[].class.getDeclaredMethods()) System.out.println(" " + method); System.out.println("methods:"); for (Method method : int[].class.getMethods()) { System.out.println(" " + method); } System.out.println(int[][][].class.getCanonicalName()); System.out.println(int[][][].class.getName()); System.out.println(int[][][].class.getSimpleName()); System.out.println(Object[][][].class.getCanonicalName()); System.out.println(Object[][][].class.getName()); System.out.println(Object[][][].class.getSimpleName()); System.out.println(Object.class.getSimpleName()); System.out.println(Object.class.getName()); System.out.println(Object.class.getCanonicalName()); EnumSet set = EnumSet.of(ModifierCode.PUBLIC, ModifierCode.CTOR); System.out.println(set); } } jpype-1.3.0/project/jpype_java/test/org/jpype/manager/TestMethodResolution.java000066400000000000000000000026401405671516700277740ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype.manager; import java.util.Arrays; import java.util.List; /** * * @author Karl Einar Nelson */ public class TestMethodResolution { static class Foo { public static void bar(Object obj, int i) { } public void bar(int i) { } } static public void main(String[] args) throws NoSuchMethodException { List foo = MethodResolution .sortMethods(Arrays.asList(TestMethodResolution.Foo.class.getDeclaredMethods())); for (MethodResolution m : foo) { System.out.println(m.executable); for (MethodResolution m1 : m.children) { System.out.println(" " + m1.executable); } } } } jpype-1.3.0/project/jpype_java/test/org/jpype/manager/TestTypeManager.java000066400000000000000000000046221405671516700267060ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype.manager; import org.jpype.manager.TypeFactoryHarness.DeletedResource; import org.jpype.manager.TypeFactoryHarness.Resource; /** * * @author nelson85 */ public class TestTypeManager { public interface MyFunction { Object apply(Object o); } public static class MyBase { void run() { } } static public void main(String[] args) { System.out.println("Create:"); TypeManager tm = new TypeManager(); TypeFactoryHarness tf = new TypeFactoryHarness(tm); tm.typeFactory = tf; System.out.println("Initialize:"); tm.init(); System.out.println(); System.out.println("=================================================="); tm.findClass(int[][][].class); MyFunction f = (Object o) -> o; tm.findClass(f.getClass()); MyFunction f2 = new MyFunction() { @Override public Object apply(Object t) { return t; } }; tm.findClass(f2.getClass()); MyBase f3 = new MyBase() { void run() { } }; tm.findClass(f3.getClass()); System.out.println("=================================================="); System.out.println(); System.out.println("Shutdown:"); tm.shutdown(); System.out.println("Leaked resources:"); int leaked = 0; for (Resource entry : tf.resourceMap.values()) { if (entry instanceof DeletedResource) continue; System.out.println(" " + entry.getName()); leaked++; } System.out.println("Resource created " + tf.value); // was 8803, reduced to 1149 System.out.println("Leaked total " + leaked); if (leaked > 0) throw new RuntimeException("Leaked resources"); } } jpype-1.3.0/project/jpype_java/test/org/jpype/manager/TypeFactoryHarness.java000066400000000000000000000346651405671516700274410ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype.manager; import java.lang.reflect.Executable; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; /** * A special version of the TypeFactory for debugging and testing. *

* This harness operates like JPype C++ layer with checks for problems and * inconsistencies that may indicate a problem with the TypeManager. * * @author nelson85 */ public class TypeFactoryHarness implements TypeFactory, TypeAudit { public long value = 0; HashMap resourceMap = new HashMap<>(); private final TypeManager typeManager; TypeFactoryHarness(TypeManager tm) { this.typeManager = tm; // Register as the audit for the TypeManager tm.audit = this; } T assertResource(long id, Class cls) { Resource resource = resourceMap.get(id); if (resource == null) throw new RuntimeException("Resource not found " + id + " " + cls.getName()); if (!cls.isInstance(resource)) throw new RuntimeException("Incorrect resource type " + id + " expected: " + cls.getName() + " found: " + resource.getClass().getName()); return (T) resource; } // @Override public long defineArrayClass( long context, Class cls, String name, long superClass, long componentPtr, int modifiers) { value++; System.out.println("defineArrayClass " + value + ": " + name); System.out.println(" modifiers: " + ModifierCode.decode(modifiers)); Resource resource = new ArrayClassResource(value, "array class " + name, cls); resourceMap.put(value, resource); return value; } @Override public long defineObjectClass(long context, Class cls, String name, long superClass, long[] interfaces, int modifiers) { value++; System.out.println("defineObjectClass " + value + ": " + name); System.out.println(" modifiers: " + ModifierCode.decode(modifiers)); if (superClass != 0) { ClassResource superClassResource = assertResource(superClass, ClassResource.class); System.out.println(" super: " + superClass + " " + superClassResource.getName()); } this.dumpResourceList("interfaces", interfaces); Resource resource = new ObjectClassResource(value, "object class " + name, cls); resourceMap.put(value, resource); return value; } @Override public long definePrimitive(long context, String name, Class cls, long boxedPtr, int modifiers) { value++; System.out.println("defineObjectClass " + value + ": " + cls.toString()); System.out.println(" modifiers: " + ModifierCode.decode(modifiers)); Resource resource = new PrimitiveClassResource(value, "primitive class " + cls.getName(), cls); resourceMap.put(value, resource); return value; } // // @Override public void assignMembers( long context, long classId, long ctorMethod, long[] methodList, long[] fieldList) { // Verify resources ClassResource classResource = assertResource(classId, ClassResource.class); try { if (ctorMethod != 0) assertResource(ctorMethod, MethodDispatchResource.class); for (int i = 0; i < methodList.length; ++i) assertResource(methodList[i], MethodDispatchResource.class); for (int i = 0; i < fieldList.length; ++i) assertResource(fieldList[i], FieldResource.class); System.out.println("assignMembers " + classId + " " + classResource.getName()); } catch (Exception ex) { System.out.println("Fail in assignClass"); ClassResource r = (ClassResource) this.resourceMap.get(classId); dump(typeManager.classMap.get(r.getResource())); throw ex; } } @Override public long defineField( long context, long classId, String name, Field field, long fieldTypeId, int modifiers) { ClassResource classResource = assertResource(classId, ClassResource.class); ClassResource fieldResource = assertResource(fieldTypeId, ClassResource.class); value++; System.out.println("defineField " + value + ":" + name); System.out.println(" modifiers: " + ModifierCode.decode(modifiers)); System.out.println(" class: " + classResource.getName()); System.out.println(" fieldType: " + fieldResource.getName()); resourceMap.put(value, new FieldResource(value, "field " + field.getName(), field)); return value; } @Override public long defineMethod( long context, long classId, String name, Executable method, long[] overloadList, int modifiers) { // Verify resources assertResource(classId, ClassResource.class); for (int i = 0; i < overloadList.length; ++i) assertResource(overloadList[i], MethodResource.class); value++; System.out.println("defineMethod " + value + ": " + name); System.out.println(" modifiers: " + ModifierCode.decode(modifiers)); System.out.flush(); resourceMap.put(value, new MethodResource(value, "method " + method.toString(), method)); return value; } @Override public void populateMethod( long context, long method, long returnType, long[] argumentTypes) { assertResource(returnType, MethodResource.class); if (returnType != 0) assertResource(returnType, ClassResource.class); for (int i = 0; i < argumentTypes.length; ++i) assertResource(argumentTypes[i], ClassResource.class); } @Override public long defineMethodDispatch( long context, long classId, String name, long[] overloadList, int modifiers) { ClassResource classResource = assertResource(classId, ClassResource.class); for (int i = 0; i < overloadList.length; ++i) assertResource(overloadList[i], MethodResource.class); value++; System.out.println("defineMethodDispatch " + value + ": '" + name + "' for " + classResource.getName()); System.out.println(" modifiers: " + ModifierCode.decode(modifiers)); this.dumpResourceList("members", overloadList); resourceMap.put(value, new MethodDispatchResource(value, "dispatch " + name)); return value; } // // Resource lastDestroyed = null; @Override public void destroy(long context, long[] resources, int sz) { System.out.println("destroy resources " + sz); for (int i = 0; i < sz; ++i) { long r = resources[i]; if (this.resourceMap.containsKey(r)) { // if (r==0) // continue; System.out.println(" destroy " + r + ": " + this.resourceMap.get(r).getName()); lastDestroyed = this.resourceMap.remove(r); if (!(lastDestroyed instanceof DeletedResource)) { this.resourceMap.put(r, new DeletedResource(lastDestroyed)); continue; } } if (lastDestroyed != null) { if (lastDestroyed instanceof MethodResource) { Class cls = ((MethodResource) lastDestroyed).getResource().getDeclaringClass(); dump(this.typeManager.classMap.get(cls)); } } throw new RuntimeException("repeat delete " + r + " at index " + i + " last " + lastDestroyed); } } // // @Override public void dump(ClassDescriptor desc) { System.out.println("ClassDescriptor: " + desc.classPtr); System.out.println(" class: " + desc.cls.toString()); System.out.println(" methodCounter:" + desc.methodCounter); if (desc.constructorDispatch != 0) { System.out.println(" ctor dispatch:"); Resource resource = this.resourceMap.get(desc.constructorDispatch); if (resource == null) System.out.println(" null"); else System.out.println(" " + resource.getEntityId() + " " + resource.getName()); } dumpResourceList("ctors", desc.constructors); dumpResourceList("method dispatch", desc.methodDispatch); dumpResourceList("methods", desc.methods); dumpResourceList("fields", desc.fields); } private void dumpResourceList(String name, long[] resourceIds) { if (resourceIds == null) return; { System.out.println(" " + name + ": " + resourceIds.length); for (long l : resourceIds) { Resource resource = this.resourceMap.get(l); if (resource == null) System.out.println(" null"); else System.out.println(" " + resource.getEntityId() + " " + resource.getName()); } } } @Override public void verifyMembers(ClassDescriptor desc) { StringBuffer failures = new StringBuffer(); String nl = System.lineSeparator(); System.out.println("Verify " + desc.cls.toString()); if (desc.methodCounter != desc.methods.length) { failures.append(" Method counter inconsistency").append(nl); } if (desc.constructorDispatch == 0 && desc.constructors != null) { failures.append(" Constructor dispatch missing").append(nl); } if (desc.constructors != null) { for (long l : desc.constructors) { if (l != 0) continue; failures.append(" Constructor is null").append(nl); break; } } for (long l : desc.methodDispatch) { if (l != 0) continue; failures.append(" Method dispatch is null").append(nl); break; } HashSet methodSet = new HashSet<>( Collections.unmodifiableList( TypeManager.filterOverridden(desc.cls, desc.cls.getDeclaredMethods()))); for (long l : desc.methods) { if (l == 0) { failures.append(" Method is null").append(nl); break; } methodSet.remove(assertResource(l, MethodResource.class).getResource()); } if (!methodSet.isEmpty()) { for (Executable e : methodSet) { failures.append(" Unaccounted method ").append(e.toString()).append(nl); } } String s = failures.toString(); if (s.isEmpty()) return; System.out.println(s); dump(desc); try { Thread.sleep(200); } catch (InterruptedException ex) { throw new RuntimeException(ex); } throw new RuntimeException("Verify failed"); } @Override public void failFindMethod(ClassDescriptor desc, Method requestedMethod) { System.out.println("Failed to find method:"); System.out.println(" requested: " + requestedMethod.toString()); System.out.println(" class: " + desc.cls.getName()); System.out.println(" declaring class: " + requestedMethod.getDeclaringClass()); System.out.println(" methods: " + desc.methodIndex.length); for (int i = 0; i < desc.methodIndex.length; ++i) { if (desc.methodIndex[i] == null) System.out.println(" null"); else System.out.println(" " + desc.methodIndex[i].toString() + " " + (desc.methodIndex[i].equals(requestedMethod))); } System.out.println(" declared methods:"); for (Method dmethod : desc.cls.getDeclaredMethods()) { System.out.println(" " + dmethod.toString()); } try { Thread.sleep(200); } catch (InterruptedException ex) { throw new RuntimeException(ex); } throw new RuntimeException("method not found " + requestedMethod); } // // @Override public void newWrapper(long context, long cls) { } public interface Resource { String getName(); Object getResource(); long getEntityId(); } public static class BaseResource implements Resource { private String name; private T object; private long id; BaseResource(long id, String name, T object) { this.id = id; this.name = name; this.object = object; } @Override public String getName() { return this.name; } @Override public T getResource() { return this.object; } @Override public long getEntityId() { return this.id; } } public static class ClassResource extends BaseResource { private ClassResource(long id, String name, Class cls) { super(id, name, cls); } } public static class ArrayClassResource extends ClassResource { private ArrayClassResource(long id, String name, Class cls) { super(id, name, cls); } } public static class ObjectClassResource extends ClassResource { private ObjectClassResource(long id, String name, Class cls) { super(id, name, cls); } } public static class PrimitiveClassResource extends ClassResource { private PrimitiveClassResource(long id, String name, Class cls) { super(id, name, cls); } } public static class FieldResource extends BaseResource { private FieldResource(long id, String name, Field cls) { super(id, name, cls); } } public static class MethodResource extends BaseResource { private MethodResource(long id, String name, Executable cls) { super(id, name, cls); } } public static class MethodDispatchResource extends BaseResource { private MethodDispatchResource(long id, String name) { super(id, name, null); } } public static class DeletedResource extends BaseResource { private DeletedResource(Resource resource) { super(resource.getEntityId(), "deleted " + resource.getName(), resource); } } // } jpype-1.3.0/project/jpype_java/test/org/jpype/pkg/000077500000000000000000000000001405671516700221325ustar00rootroot00000000000000jpype-1.3.0/project/jpype_java/test/org/jpype/pkg/JPypePackageNGTest.java000066400000000000000000000050661405671516700263740ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype.pkg; import java.net.URI; import java.nio.file.Path; import java.util.Arrays; import java.util.Map; import static org.testng.Assert.*; import org.testng.annotations.Test; /** * * @author nelson85 */ public class JPypePackageNGTest { public JPypePackageNGTest() { } @Test public void testGetPackage() { assertTrue(JPypePackageManager.isPackage("java.lang")); JPypePackage pkg = new JPypePackage("java.lang"); for (Map.Entry e : pkg.contents.entrySet()) { Path p = JPypePackageManager.getPath(e.getValue()); JPypePackage.isPublic(p); } } @Test public void testBase() { assertTrue(JPypePackageManager.isPackage("java")); JPypePackage pkg = new JPypePackage("java"); for (Map.Entry e : pkg.contents.entrySet()) { System.out.println(e.getKey()); } } @Test public void testOrg() { assertTrue(JPypePackageManager.isPackage("org")); JPypePackage pkg = new JPypePackage("org"); for (Map.Entry e : pkg.contents.entrySet()) { System.out.println(e.getKey()); } } /** * Test of getObject method, of class JPypePackage. */ @Test public void testGetObject() { System.out.println("getObject"); JPypePackage instance = new JPypePackage("java.lang"); Object expResult = Object.class; Object result = instance.getObject("Object"); assertEquals(result, expResult); } /** * Test of getContents method, of class JPypePackage. */ @Test public void testGetContents() { System.out.println("getContents"); JPypePackage instance = new JPypePackage("java.lang"); String[] expResult = new String[] { "Enum", "ClassValue", "String" }; String[] result = Arrays.copyOfRange(instance.getContents(), 0, 3); assertEquals(result, expResult); } } jpype-1.3.0/project/jpype_java/test/org/jpype/pkg/ListPackage.java000066400000000000000000000021131405671516700251610ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype.pkg; /** * * @author nelson85 */ public class ListPackage { public static void main(String[] args) { JPypePackage pkg = new JPypePackage("java.lang"); System.out.println(pkg.contents.size()); for (String s : pkg.getContents()) { System.out.println(s); } System.out.println(pkg.getObject("Class")); } } jpype-1.3.0/project/snippet/000077500000000000000000000000001405671516700160065ustar00rootroot00000000000000jpype-1.3.0/project/snippet/assertRaises.py000066400000000000000000000011131405671516700210240ustar00rootroot00000000000000 class AssertRaises(object): def __init__(self, expected): self.expected = expected def __enter__(self): return self def __exit__(self, exc_type, exc_value, tb): if exc_type is None: try: exc_name = self.expected.__name__ except AttributeError: exc_name = str(self.expected) raise AssertionError("{0} not raised".format(exc_name)) if not issubclass(exc_type, self.expected): # let unexpected exceptions pass through return False return True jpype-1.3.0/project/utility/000077500000000000000000000000001405671516700160275ustar00rootroot00000000000000jpype-1.3.0/project/utility/alter.py000066400000000000000000000022021405671516700175040ustar00rootroot00000000000000# Utility used to alter a Java jar file to date it in the future. # This was needed to intentionally trigger a version error. import jpype import jpype.imports jpype.startJVM() from java.util.jar import JarOutputStream from java.util.jar import JarInputStream from java.util.zip import CRC32 from java.io import File from java.io import FileInputStream from java.io import FileOutputStream jar = JarInputStream(FileInputStream(File("build/lib/org.jpype.jar"))) manifest = jar.getManifest() target = JarOutputStream(FileOutputStream(File("build/lib/org.jpype2.jar")), manifest) while 1: entry = jar.getNextEntry() if not entry: break out = [] l3 = 512 while 1: bt = jpype.JArray(jpype.JByte)(l3) l = jar.read(bt, 0, l3) if l == -1: break out.append((l, bt)) if out: out[0][1][7] = 57 crc = CRC32() for v in out: crc.update(v[1], 0, v[0]) entry.setCrc(crc.getValue()) entry.setCompressedSize(-1) target.putNextEntry(entry) for v in out: target.write(v[1], 0, v[0]) target.closeEntry() target.close() jpype-1.3.0/project/utility/remove.py000066400000000000000000000013531405671516700177000ustar00rootroot00000000000000# This script was used to scrub the harness of old code # First a set of sed patterns found all the harness classes # that are in used directly. They were moved out of place using, # this script, then those that were used indirectly were moved # back in place. import glob import re import os with open("keep", "r") as fd: lines = fd.readlines() lines = [i.strip() for i in lines] keep = set(lines) for fl in glob.iglob('harness/**/*.java', recursive=True): m = re.match('.*(jpype.*).java', fl) name = m.group(1).replace('/', '.') if name in keep: continue m = re.match('(.*)/[^/]*.java', fl) os.makedirs(os.path.join("old", m.group(1)), exist_ok=True) os.rename(fl, os.path.join("old", fl)) jpype-1.3.0/project/utility/testDoc.py000066400000000000000000000040011405671516700200010ustar00rootroot00000000000000import _jpype import jpype from jpype.types import * import jpype.imports jpype.startJVM(classpath=['gson-2.8.5.jar', 'gson-2.8.5-javadoc.jar', 'project/jpype_java/dist/*', 'project/jpype_java/jdk-11.0.7_doc-all.zip']) import org html = JClass("org.jpype.html.Html") hw = JClass("org.jpype.html.HtmlWriter") #jdz = JClass("org.jpype.javadoc.JavadocZip")(Paths.get("project/jpype_java/jdk-8u251-docs-all.zip")) jde = JClass("org.jpype.javadoc.JavadocExtractor") #jdf = JClass("org.jpype.javadoc.JavadocTransformer")() #jdr = JClass("org.jpype.javadoc.JavadocRenderer")() current = None def renderClass(cls): global current jd = jde.getDocumentation(cls) #jis = jdz.getInputStream(cls) if jd is None: return print("=========================================================") print("CLASS", cls) print(jd.description) print(jd.ctors) print("---------------------------------------------------------") if jd.methods is not None: for p, v in jd.methods.items(): print(v) print("- - - - - - - - - - - - - - - - - - - - - - - - - - - - -") print("---------------------------------------------------------") if jd.fields is not None: for p, v in jd.fields.items(): print(v) print("- - - - - - - - - - - - - - - - - - - - - - - - - - - - -") print("=========================================================") def renderPackage(pkg): for i in dir(pkg): print("Test", i) try: p = getattr(pkg, i) except Exception: continue if isinstance(p, _jpype._JPackage): renderPackage(p) continue if isinstance(p, jpype.JClass): renderClass(p) try: renderPackage(jpype.JPackage('com.google.gson')) except org.jpype.javadoc.JavadocException as ex: print("Javadoc Error: ", ex.message()) print(hw.asString(ex.node)) raise ex except Exception as ex: print("Error in") print(hw.asString(current)) raise ex jpype-1.3.0/project/utility/testMemoryExh.py000066400000000000000000000050511405671516700212170ustar00rootroot00000000000000# This is the audit script for checking the GC linker. # # It beats to memory to see if everything holds up, but not suitable for # the test suite. It is run in conjuction with the printf statement in # jp_gc.cpp to see how aggressive we are being about running the gc. # The goal is to keep the memory as low as possible while still maintaining # good speed. It has to be checked with 3 different block sizes to # verify function (<1k, 10k, >1Mb) as different behaviors occur at different # usage points. from os import path import _jpype import jpype from jpype.types import * import numpy as np import gc import time # print(gc.callbacks) # # def callHook(*args): # jpype.java.lang.System.gc() # # gc.callbacks.append(callHook) trials = 200000 tally = np.zeros((trials,), dtype=np.int8) class DestructionTracker: del_calls = 0 init_calls = 0 def __init__(self, i, obj): self.index = i self.obj = obj DestructionTracker.init_calls += 1 tally[i] = 1 super().__init__() def __del__(self): tally[self.index] += 1 DestructionTracker.del_calls += 1 def callback(self, message): pass if __name__ == '__main__': jpype.startJVM(classpath=['test/classes', 'project/jpype_java/dist/*'], convertStrings=True) print() kB = (1024 / 8) MB = (1024**2 / 8) fixture = JClass("jpype.common.Fixture")() for i in range(trials): x = np.arange(int(10 * kB), dtype=np.int64) interface = jpype.JProxy("java.io.Serializable", dict={'callback': DestructionTracker(i, x).callback}) interface_container = fixture.callObject(interface) if (i % 1000) == 0: stats = _jpype.gcStats() print("created=", DestructionTracker.init_calls, " destroyed=", DestructionTracker.del_calls, " delta=", DestructionTracker.init_calls - DestructionTracker.del_calls, " current=", stats['current'], " min=", stats['min'], " max=", stats['max'], " triggered=", stats['triggered'], ) time.sleep(1) # print(_jpype.gcStats()) del interface, interface_container # if DestructionTracker.del_calls != 0: # print(f'{i} We have deleted something: {DestructionTracker.del_calls}') # else: # print(f'{i} Still no deletion on it {i}\n', end="") print() print(np.sum(tally == 2)) jpype.shutdownJVM() print(np.sum(tally == 2)) jpype-1.3.0/resolve.sh000066400000000000000000000005361405671516700146750ustar00rootroot00000000000000#!/bin/sh # This is used to pull dependencies needed for this package # drill has a bunch of dependencies, so we are going to use ivy to collect it all at once. wget -nc "https://repo1.maven.org/maven2/org/apache/ivy/ivy/2.5.0/ivy-2.5.0.jar" -P lib java -jar lib/ivy-2.5.0.jar -ivy ivy.xml -retrieve 'lib/[artifact]-[revision](-[classifier]).[ext]' jpype-1.3.0/setup.cfg000066400000000000000000000001431405671516700144750ustar00rootroot00000000000000[alias] test=pytest [tool:pytest] addopts = --verbose testpaths = test jpype/_pyinstaller jpype-1.3.0/setup.py000066400000000000000000000073221405671516700143740ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import sys from pathlib import Path from setuptools import setup from setuptools import Extension import glob if sys.version_info[0] < 3 and sys.version_info[1] < 5: raise RuntimeError("JPype requires Python 3.5 or later") import setupext if '--android' in sys.argv: platform = 'android' sys.argv.remove('--android') else: platform = sys.platform jpypeLib = Extension(name='_jpype', **setupext.platform.Platform( include_dirs=[Path('native', 'common', 'include'), Path('native', 'python', 'include'), Path('native', 'embedded', 'include')], sources=sorted(map(str, list(Path('native', 'common').glob('*.cpp'))+ list(Path('native', 'python').glob('*.cpp'))+ list(Path('native', 'embedded').glob('*.cpp')))), platform=platform, )) jpypeJar = Extension(name="org.jpype", sources=sorted(map(str, Path("native", "java").glob("**/*.java"))), language="java", libraries=["lib/asm-8.0.1.jar"] ) setup( name='JPype1', version='1.3.0', description='A Python to Java bridge.', long_description=open('README.rst').read(), license='License :: OSI Approved :: Apache Software License', author='Steve Menard', author_email='devilwolf@users.sourceforge.net', maintainer='Luis Nell', maintainer_email='cooperate@originell.org', url='https://github.com/jpype-project/jpype', platforms=[ 'Operating System :: Microsoft :: Windows', 'Operating System :: POSIX', 'Operating System :: Unix', 'Operating System :: MacOS', ], classifiers=[ 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Topic :: Software Development', 'Topic :: Scientific/Engineering', ], packages=['jpype', 'jpype._pyinstaller'], package_dir={'jpype': 'jpype', }, package_data={'jpype': ['*.pyi']}, install_requires=['typing_extensions ; python_version< "3.8"'], tests_require=['pytest'], extras_require={ 'tests': [ 'pytest', ], 'docs': [ 'readthedocs-sphinx-ext', 'sphinx', 'sphinx-rtd-theme', ], }, cmdclass={ 'build_ext': setupext.build_ext.BuildExtCommand, 'test_java': setupext.test_java.TestJavaCommand, 'sdist': setupext.sdist.BuildSourceDistribution, 'test': setupext.pytester.PyTest, }, zip_safe=False, ext_modules=[jpypeJar, jpypeLib, ], distclass=setupext.dist.Distribution, entry_points={ 'pyinstaller40': [ 'hook-dirs = jpype._pyinstaller.entry_points:get_hook_dirs', 'tests = jpype._pyinstaller.entry_points:get_PyInstaller_tests', ], }, ) jpype-1.3.0/setupext/000077500000000000000000000000001405671516700145375ustar00rootroot00000000000000jpype-1.3.0/setupext/__init__.py000066400000000000000000000016231405671516700166520ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** from . import utils from . import dist from . import platform from . import build_ext from . import test_java from . import sdist from . import pytester jpype-1.3.0/setupext/build_ext.py000066400000000000000000000275201405671516700170760ustar00rootroot00000000000000# -*- coding: utf-8 -*- # ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import os from setuptools.command.build_ext import build_ext import sys import subprocess import distutils.cmd import distutils.log from distutils.errors import DistutilsPlatformError from distutils.dir_util import copy_tree import glob import re import shlex import shutil import sysconfig # This setup option constructs a prototype Makefile suitable for compiling # the _jpype extension module. It is intended to help with development # of the extension library on unix systems. This works only on unix systems. # # To create a Makefile use # python setup.py build_ext --makefile # # Then edit with the desired options class FeatureNotice(Warning): """ indicate notices about features """ class Makefile(object): compiler_type = "unix" def __init__(self, actual): self.actual = actual self.compile_command = None self.compile_pre = None self.compile_post = None self.objects = [] self.sources = [] def captureCompile(self, x): command = x[0] x = x[1:] includes = [i for i in x if i.startswith("-I")] x = [i for i in x if not i.startswith("-I")] i0 = None i1 = None for i, v in enumerate(x): if v == '-c': i1 = i elif v == '-o': i0 = i pre = set(x[:i1]) post = x[i0 + 2:] self.compile_command = command self.compile_pre = pre self.compile_post = post self.includes = includes self.sources.append(x[i1 + 1]) def captureLink(self, x): self.link_command = x[0] x = x[1:] i = x.index("-o") self.library = x[i + 1] del x[i] del x[i] self.objects = [i for i in x if i.endswith(".o")] self.link_options = [i for i in x if not i.endswith(".o")] u = self.objects[0].split("/") self.build_dir = "/".join(u[:2]) def compile(self, *args, **kwargs): self.actual.spawn = self.captureCompile rc = self.actual.compile(*args, **kwargs) return rc def _need_link(self, *args): return True def link_shared_object(self, *args, **kwargs): self.actual._need_link = self._need_link self.actual.spawn = self.captureLink rc = self.actual.link_shared_object(*args, **kwargs) self.write() return rc def detect_language(self, x): return self.actual.detect_language(x) def write(self): print("Write makefile") library = os.path.basename(self.library) link_command = self.link_command compile_command = self.compile_command compile_pre = " ".join(list(self.compile_pre)) compile_post = " ".join(list(self.compile_post)) build = self.build_dir link_flags = " ".join(self.link_options) includes = " ".join(self.includes) sources = " \\\n ".join(self.sources) with open("Makefile", "w") as fd: print("LIB = %s" % library, file=fd) print("CC = %s" % compile_command, file=fd) print("LINK = %s" % link_command, file=fd) print("CFLAGS = %s %s" % (compile_pre, compile_post), file=fd) print("INCLUDES = %s" % includes, file=fd) print("BUILD = %s" % build, file=fd) print("LINKFLAGS = %s" % link_flags, file=fd) print("SRCS = %s" % sources, file=fd) print(""" all: $(LIB) rwildcard=$(foreach d,$(wildcard $(1:=/*)),$(call rwildcard,$d,$2) $(filter $(subst *,%,$2),$d)) #build/src/jp_thunk.cpp: $(call rwildcard,native/java,*.java) # python setup.py build_thunk DEPDIR = build/deps $(DEPDIR): ; @mkdir -p $@ DEPFILES := $(SRCS:%.cpp=$(DEPDIR)/%.d) deps: $(DEPFILES) %/: echo $@ $(DEPDIR)/%.d: %.cpp mkdir -p $(dir $@) $(CC) $(INCLUDES) -MT $(patsubst $(DEPDIR)%,'$$(BUILD)%',$(patsubst %.d,%.o,$@)) -MM $< -o $@ OBJS = $(addprefix $(BUILD)/, $(SRCS:.cpp=.o)) $(BUILD)/%.o: %.cpp mkdir -p $(dir $@) $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ $(LIB): $(OBJS) $(LINK) $(OBJS) $(LINKFLAGS) -o $@ -include $(DEPFILES) """, file=fd) # Customization of the build_ext class BuildExtCommand(build_ext): """ Override some behavior in extension building: 1. handle compiler flags for different compilers via a dictionary. 2. try to disable warning -Wstrict-prototypes is valid for C/ObjC but not for C++ """ user_options = build_ext.user_options + [ ('android', None, 'configure for android'), ('makefile', None, 'Build a makefile for extensions'), ('jar', None, 'Build the jar only'), ] def initialize_options(self, *args): """omit -Wstrict-prototypes from CFLAGS since its only valid for C code.""" self.android = False self.makefile = False self.jar = False import distutils.sysconfig cfg_vars = distutils.sysconfig.get_config_vars() replacement = { '-Wstrict-prototypes': '', '-Wimplicit-function-declaration': '', } tracing = self.distribution.enable_tracing # Arguments to remove so we set debugging and optimization level remove_args = ['-O0', '-O1', '-O2', '-O3', '-g'] for k, v in cfg_vars.items(): if not isinstance(v, str): continue if not k == "OPT" and not "FLAGS" in k: continue args = v.split() for r in remove_args: args = list(filter((r).__ne__, args)) cfg_vars[k] = " ".join(args) super().initialize_options() def _set_cflags(self): # set compiler flags c = self.compiler.compiler_type jpypeLib = [i for i in self.extensions if i.name == '_jpype'][0] if c == 'unix' and self.distribution.enable_coverage: jpypeLib.extra_compile_args.extend( ['-ggdb', '--coverage', '-ftest-coverage']) jpypeLib.extra_compile_args = ['-O0' if x == '-O2' else x for x in jpypeLib.extra_compile_args] jpypeLib.extra_link_args.extend(['--coverage']) if c == 'unix' and self.distribution.enable_tracing: jpypeLib.extra_compile_args = ['-O0' if x == '-O2' else x for x in jpypeLib.extra_compile_args] def build_extensions(self): if self.makefile: self.compiler = Makefile(self.compiler) self.force = True jpypeLib = [i for i in self.extensions if i.name == '_jpype'][0] tracing = self.distribution.enable_tracing self._set_cflags() if tracing: jpypeLib.define_macros.append(('JP_TRACING_ENABLE', 1)) coverage = self.distribution.enable_coverage if coverage: jpypeLib.define_macros.append(('JP_INSTRUMENTATION', 1)) # has to be last call print("Call build extensions") super().build_extensions() def build_extension(self, ext): if ext.language == "java": return self.build_java_ext(ext) if self.jar: return print("Call build ext") return super().build_extension(ext) def copy_extensions_to_source(self): build_py = self.get_finalized_command('build_py') for ext in self.extensions: if ext.language == "java": fullname = self.get_ext_fullname("JAVA") filename = ext.name + ".jar" else: fullname = self.get_ext_fullname(ext.name) filename = self.get_ext_filename(fullname) modpath = fullname.split('.') package = '.'.join(modpath[:-1]) package_dir = build_py.get_package_dir(package) dest_filename = os.path.join(package_dir, os.path.basename(filename)) src_filename = os.path.join(self.build_lib, filename) # Always copy, even if source is older than destination, to ensure # that the right extensions for the current Python/platform are # used. distutils.file_util.copy_file( src_filename, dest_filename, verbose=self.verbose, dry_run=self.dry_run ) if ext._needs_stub: self.write_stub(package_dir or os.curdir, ext, True) def build_java_ext(self, ext): """Run command.""" java = self.distribution.enable_build_jar javac = "javac" try: if os.path.exists(os.path.join(os.environ['JAVA_HOME'], 'bin', 'javac')): javac = '"%s"' % os.path.join(os.environ['JAVA_HOME'], 'bin', 'javac') except KeyError: pass jar = "jar" try: if os.path.exists(os.path.join(os.environ['JAVA_HOME'], 'bin', 'jar')): jar = '"%s"' % os.path.join(os.environ['JAVA_HOME'], 'bin', 'jar') except KeyError: pass # Try to use the cache if we are not requested build if not java: src = os.path.join('native', 'jars') dest = os.path.dirname(self.get_ext_fullpath("JAVA")) if os.path.exists(src): distutils.log.info("Using Jar cache") copy_tree(src, dest) return classpath = "." if ext.libraries: classpath = os.path.pathsep.join(ext.libraries) distutils.log.info( "Jar cache is missing, using --enable-build-jar to recreate it.") coverage = self.distribution.enable_coverage target_version = "1.8" # build the jar try: dirname = os.path.dirname(self.get_ext_fullpath("JAVA")) jarFile = os.path.join(dirname, ext.name + ".jar") build_dir = os.path.join(self.build_temp, ext.name, "classes") os.makedirs(build_dir, exist_ok=True) os.makedirs(dirname, exist_ok=True) cmd1 = shlex.split('%s -cp "%s" -d "%s" -g:none -source %s -target %s -encoding UTF-8' % (javac, classpath, build_dir, target_version, target_version)) cmd1.extend(ext.sources) debug = "-g:none" if coverage: debug = "-g:lines,vars,source" os.makedirs("build/classes", exist_ok=True) self.announce(" %s" % " ".join(cmd1), level=distutils.log.INFO) subprocess.check_call(cmd1) try: for file in glob.iglob("native/java/**/*.*", recursive=True): if file.endswith(".java") or os.path.isdir(file): continue p = os.path.join(build_dir, os.path.relpath(file, "native/java")) print("Copy file", file, p) shutil.copyfile(file, p) except Exception as ex: print("FAIL", ex) pass cmd3 = shlex.split( '%s cvf "%s" -C "%s" .' % (jar, jarFile, build_dir)) self.announce(" %s" % " ".join(cmd3), level=distutils.log.INFO) subprocess.check_call(cmd3) except subprocess.CalledProcessError as exc: distutils.log.error(exc.output) raise DistutilsPlatformError("Error executing {}".format(exc.cmd)) jpype-1.3.0/setupext/dist.py000066400000000000000000000026031405671516700160550ustar00rootroot00000000000000# -*- coding: utf-8 -*- # ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** from setuptools.dist import Distribution as _Distribution # Add a new global option to the setup.py script. class Distribution(_Distribution): global_options = [ ('enable-build-jar', None, 'Build the java jar portion'), ('enable-tracing', None, 'Set for tracing for debugging'), ('enable-coverage', None, 'Instrument c++ code for code coverage measuring'), ] + _Distribution.global_options def parse_command_line(self): self.enable_tracing = False self.enable_build_jar = False self.enable_coverage = False return _Distribution.parse_command_line(self) jpype-1.3.0/setupext/platform.py000066400000000000000000000123641405671516700167430ustar00rootroot00000000000000# -*- coding: utf-8 -*- # ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import setupext import os import sys import sysconfig import distutils.log # This handles all of the work to make our platform specific extension options. def Platform(include_dirs=None, sources=None, platform=sys.platform): if include_dirs is None: include_dirs = [] if sources is None: sources = [] platform_specific = { 'include_dirs': include_dirs, 'sources': setupext.utils.find_sources(sources), } fallback_jni = os.path.join('native', 'jni_include') # try to include JNI first from eventually given JAVA_HOME, then from distributed java_home = os.getenv('JAVA_HOME', '') found_jni = False if os.path.exists(java_home): platform_specific['include_dirs'] += [os.path.join(java_home, 'include')] # check if jni.h can be found for d in platform_specific['include_dirs']: if os.path.exists(os.path.join(str(d), 'jni.h')): distutils.log.info("Found native jni.h at %s", d) found_jni = True break if not found_jni: distutils.log.warn('Falling back to provided JNI headers, since your provided' ' JAVA_HOME "%s" does not provide jni.h', java_home) if not found_jni: platform_specific['include_dirs'] += [fallback_jni] platform_specific['extra_link_args'] = [] distutils.log.info("Configure platform to", platform) static = True if platform == 'win32': distutils.log.info("Add windows settings") # platform_specific['libraries'] = ['Advapi32'] platform_specific['define_macros'] = [('WIN32', 1)] if sys.version > '3': platform_specific['extra_compile_args'] = [ '/Zi', '/EHsc', '/std:c++14'] else: platform_specific['extra_compile_args'] = ['/Zi', '/EHsc'] # platform_specific['extra_link_args'] = ['/DEBUG'] jni_md_platform = 'win32' elif platform == 'darwin': distutils.log.info("Add darwin settings") platform_specific['libraries'] = ['dl'] platform_specific['define_macros'] = [('MACOSX', 1)] platform_specific['extra_compile_args'] = ['-g0', '-std=c++11', '-O2'] jni_md_platform = 'darwin' elif platform.startswith('linux'): distutils.log.info("Add linux settings") platform_specific['libraries'] = ['dl'] platform_specific['extra_compile_args'] = ['-g0', '-std=c++11', '-O2'] jni_md_platform = 'linux' elif platform.startswith('aix7'): distutils.log.info("Add aix settings") platform_specific['libraries'] = ['dl'] platform_specific['extra_compile_args'] = ['-g3', '-std=c++11', '-O2'] jni_md_platform = 'aix7' elif platform.startswith('freebsd'): distutils.log.info("Add freebsd settings") jni_md_platform = 'freebsd' elif platform.startswith('android'): distutils.log.info("Add android settings") platform_specific['libraries'] = ['dl', 'c++_shared', 'SDL2'] platform_specific['extra_compile_args'] = ['-g0', '-std=c++11', '-fexceptions', '-frtti', '-O2'] print("PLATFORM_SPECIFIC:", platform_specific) jni_md_platform = 'linux' static = False elif platform == 'zos': distutils.log.info("Add zos settings") jni_md_platform = 'zos' elif platform == 'sunos5': distutils.log.info("Add solaris settings") jni_md_platform = 'solaris' else: jni_md_platform = '' distutils.log.warn("Your platform '%s' is not being handled explicitly." " It may work or not!", platform) # This code is used to include python library in the build when starting Python from # within Java. It will be used in the future, but is not currently required. # if static and sysconfig.get_config_var('BLDLIBRARY') is not None: # platform_specific['extra_link_args'].append(sysconfig.get_config_var('BLDLIBRARY')) if found_jni: distutils.log.info("Add JNI directory %s" % os.path.join(java_home, 'include', jni_md_platform)) platform_specific['include_dirs'] += \ [os.path.join(java_home, 'include', jni_md_platform)] return platform_specific # include this stolen from FindJNI.cmake """ FIND_PATH(JAVA_INCLUDE_PATH2 jni_md.h ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH}/win32 ${JAVA_INCLUDE_PATH}/linux ${JAVA_INCLUDE_PATH}/freebsd ${JAVA_INCLUDE_PATH}/solaris ${JAVA_INCLUDE_PATH}/hp-ux ${JAVA_INCLUDE_PATH}/alpha )""" jpype-1.3.0/setupext/pytester.py000066400000000000000000000024171405671516700167740ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import sys from setuptools.command.test import test as TestCommand class PyTest(TestCommand): user_options = [("pytest-args=", "a", "Arguments to pass to pytest")] def initialize_options(self): TestCommand.initialize_options(self) self.pytest_args = "" def run_tests(self): self.run_command("test_java") import shlex # import here, cause outside the eggs aren't loaded import pytest errno = pytest.main(shlex.split(self.pytest_args)) sys.exit(errno) jpype-1.3.0/setupext/sdist.py000066400000000000000000000040541405671516700162420ustar00rootroot00000000000000# -*- coding: utf-8 -*- # ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import os import distutils from distutils.dir_util import copy_tree, remove_tree, mkpath from distutils.file_util import copy_file from setuptools.command.sdist import sdist # Customization of the sdist class BuildSourceDistribution(sdist): """ Override some behavior on sdist Copy the build/lib to native/jars to remove javac/jdk dependency """ def run(self): dest = os.path.join('native', 'jars') # We need to build a jar cache for the source distribution cmd = self.distribution.get_command_obj('build_ext') # Call with jar only option cmd.jar = True self.run_command('build_ext') # Find out the location of the jar file dirname = os.path.dirname(cmd.get_ext_fullpath("JAVA")) jarFile = os.path.join(dirname, "org.jpype.jar") # Also build the test harness files self.run_command("test_java") if not os.path.exists(jarFile): distutils.log.error("Jar source file is missing from build") raise distutils.errors.DistutilsPlatformError( "Error copying jar file") mkpath(dest) copy_file(jarFile, dest) # Collect the sources sdist.run(self) # Clean up the jar cache after sdist remove_tree(dest) jpype-1.3.0/setupext/test_java.py000066400000000000000000000056671405671516700171070ustar00rootroot00000000000000# -*- coding: utf-8 -*- # ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import sys import os import subprocess import distutils.cmd import distutils.log import glob import re import shlex def getJavaVersion(javac): # Find Java version version_str = os.popen('"%s" -version' % javac).read() result = re.match(r'javac ([0-9]+)\.([0-9]+)\..*', version_str) if not result: return 8 if int(result.group(1)) > 1: return int(result.group(1)) return int(result.group(2)) def compileJava(): javac = "javac" try: javac0 = os.path.join(os.environ['JAVA_HOME'], 'bin', 'javac') if os.name == "nt": javac0 += ".exe" if os.path.exists(javac0): javac = javac0 except KeyError: print("No JAVA_HOME set") pass print("JAVAC =", javac) version = getJavaVersion(javac) srcs = glob.glob('test/harness/jpype/**/*.java', recursive=True) srcs.extend(glob.glob('test/harness/org/**/*.java', recursive=True)) exports = "" if version > 7: srcs.extend(glob.glob('test/harness/java8/**/*.java', recursive=True)) if version > 8: srcs.extend(glob.glob('test/harness/java9/**/*.java', recursive=True)) exports = "--add-exports java.base/jdk.internal.reflect=ALL-UNNAMED" cmd = shlex.split( '"%s" -d test/classes %s -g:lines,vars,source' % (javac, exports)) os.makedirs("test/classes", exist_ok=True) cmd.extend(srcs) return cmd class TestJavaCommand(distutils.cmd.Command): """A custom command to create jar file during test.""" description = 'run javac to make test harness' user_options = [] def initialize_options(self): """Set default values for options.""" pass def finalize_options(self): """Post-process options.""" pass def run(self): """Run command.""" if os.path.exists(os.path.join("test", "classes")): distutils.log.info("Skip building Java testbench") return cmdStr = compileJava() self.announce(" %s" % " ".join(cmdStr), level=distutils.log.INFO) subprocess.check_call(cmdStr) subprocess.check_call(shlex.split("javadoc test/harness/jpype/doc/Test.java -d test/classes/")) jpype-1.3.0/setupext/utils.py000066400000000000000000000021741405671516700162550ustar00rootroot00000000000000# -*- coding: utf-8 -*- # ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import os import codecs import glob def read_utf8(path, *parts): filename = os.path.join(os.path.dirname(path), *parts) return codecs.open(filename, encoding='utf-8').read() def find_sources(roots=[]): cpp_files = [] for root in roots: for filename in glob.iglob(str(root)): cpp_files.append(filename) return cpp_files jpype-1.3.0/test-requirements.txt000066400000000000000000000000541405671516700171160ustar00rootroot00000000000000pytest==4.6.9 pyinstaller==4.0 jedi==0.17.0 jpype-1.3.0/test/000077500000000000000000000000001405671516700136355ustar00rootroot00000000000000jpype-1.3.0/test/build.xml000066400000000000000000000031401405671516700154540ustar00rootroot00000000000000 jpype-1.3.0/test/harness/000077500000000000000000000000001405671516700153005ustar00rootroot00000000000000jpype-1.3.0/test/harness/java8/000077500000000000000000000000001405671516700163115ustar00rootroot00000000000000jpype-1.3.0/test/harness/java8/jpype/000077500000000000000000000000001405671516700174405ustar00rootroot00000000000000jpype-1.3.0/test/harness/java8/jpype/lambda/000077500000000000000000000000001405671516700206605ustar00rootroot00000000000000jpype-1.3.0/test/harness/java8/jpype/lambda/Test1.java000066400000000000000000000021051405671516700225210ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.lambda; import java.util.function.Function; public class Test1 { public Function getFunction() { return new Function() { public Double apply(Double d) { return d + 1; } }; } public Function getLambda() { return (Double d) -> (d + 1); } } jpype-1.3.0/test/harness/java9/000077500000000000000000000000001405671516700163125ustar00rootroot00000000000000jpype-1.3.0/test/harness/java9/jpype/000077500000000000000000000000001405671516700174415ustar00rootroot00000000000000jpype-1.3.0/test/harness/java9/jpype/method/000077500000000000000000000000001405671516700207215ustar00rootroot00000000000000jpype-1.3.0/test/harness/java9/jpype/method/Caller.java000066400000000000000000000040021405671516700227620ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.method; import jdk.internal.reflect.CallerSensitive; /** * Caller sensitive methods need special handling. * * So we need to test each possible path (different return types and arguments). * * We will pretend our methods are also CallerSensitive. */ public class Caller { @CallerSensitive public static Object callObjectStatic() { return new Caller(); } @CallerSensitive public Object callObjectMember() { return new Caller(); } @CallerSensitive public static void callVoidStatic() { } @CallerSensitive public void callVoidMember() { } @CallerSensitive public static int callIntegerStatic() { return 123; } @CallerSensitive public int callIntegerMember() { return 123; } @CallerSensitive public Object callArgs(Object a, Object b) { return b; } @CallerSensitive public int callArg1(int a) { return a; } @CallerSensitive public Object callVarArgs(Object a, Object... b) { return b; } public Class callStackWalker1() { return StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE).getCallerClass(); } @CallerSensitive public Class callStackWalker2() { return StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE).getCallerClass(); } }; jpype-1.3.0/test/harness/jpype/000077500000000000000000000000001405671516700164275ustar00rootroot00000000000000jpype-1.3.0/test/harness/jpype/array/000077500000000000000000000000001405671516700175455ustar00rootroot00000000000000jpype-1.3.0/test/harness/jpype/array/Test2.java000066400000000000000000000016051405671516700214130ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.array; public class Test2 { public Object[] getValue() { return new Object[0]; } public Object test(Object o) { return null; } } jpype-1.3.0/test/harness/jpype/array/TestArray.java000066400000000000000000000026571405671516700223400ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.array; public class TestArray { public TestArray() { } public int[] i = { 12234, 1234, 234, 1324, 424, 234, 234, 142, 5, 251, 242, 35, 235, 62, 1235, 46, 245132, 51, 2, 3, 4 }; public Object[] getSubClassArray() { return new Integer[] { 1, 2 }; } public Object getArrayAsObject() { return new String[] { "aaa", "bbb" }; } public char[] getCharArray() { return new char[] { 'a', 'v', 'c', 'd' }; } public byte[] getByteArray() { String s = "avcd"; return s.getBytes(); } public Object testObject(Object obj) { return obj; } public Object testInt(int[] obj) { return obj; } } jpype-1.3.0/test/harness/jpype/attr/000077500000000000000000000000001405671516700174015ustar00rootroot00000000000000jpype-1.3.0/test/harness/jpype/attr/ClassWithBuffer.java000066400000000000000000000016411405671516700233010ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.attr; import java.awt.image.BufferStrategy; public class ClassWithBuffer { public BufferStrategy bufferStrategy; public void foo() { System.out.println("foo"); } } jpype-1.3.0/test/harness/jpype/attr/Holder.java000066400000000000000000000014401405671516700214600ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.attr; public class Holder { public String f; } jpype-1.3.0/test/harness/jpype/attr/SubHolder.java000066400000000000000000000014761405671516700221430ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.attr; public class SubHolder extends Holder implements java.io.Serializable { } jpype-1.3.0/test/harness/jpype/attr/SyntheticMethods.java000066400000000000000000000020661405671516700235460ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.attr; import java.util.List; public class SyntheticMethods { public static interface GenericInterface { void foo(T value); } public static class GenericImpl implements GenericInterface { public List mListValue = null; public void foo(List value) { mListValue = value; } } } jpype-1.3.0/test/harness/jpype/attr/Test1.java000066400000000000000000000047771405671516700212630ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.attr; public class Test1 { private String mBigString; public Test1() { StringBuffer sb = new StringBuffer(4001); for (int i = 0; i < 4000; i++) { sb.append("A"); } mBigString = sb.toString(); } public String getBigString() { return mBigString; } public String toString() { return "aaa"; } public static String[] testStaticString(String s1, String s2) { return new String[] { s1, s2 }; } public static String testStaticHolder(Holder h) { return h.f; } public String[] testString(String s1, String s2) { return new String[] { s1, s2 }; } public String[] testStringArray(String[] vals) { return vals; } public String stringValue = "Foo"; public char charValue = 'a'; public static Object objectValue = (int) 234; public static void reset() { objectValue = (int) 234; } public Object getSubClass() { return new SubHolder(); } public void callWithClass(Class c) { } public void test1Method() { } public boolean mBooleanValue = false; public void setBoolean(boolean b) { mBooleanValue = b; } public byte mByteValue; public void setByte(byte b) { mByteValue = b; } public short mShortValue = 0; public void setShort(short s) { mShortValue = s; } public int mIntValue = 0; public void setInt(int i) { mIntValue = i; } public long mLongValue = 0; public void setLong(long l) { mLongValue = l; } public String callWithSomething(Object obj) { return "Object"; } public String callWithSomething(Class obj) { return "Class"; } public Test1 delete(String arg1, String arg2) { System.out.println("Overloaded test 1 called"); return null; } } jpype-1.3.0/test/harness/jpype/attr/Test2.java000066400000000000000000000020421405671516700212430ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.attr; public class Test2 extends Test1 { public Test2() { super(); } public void test2Method() { } public String toString(String foo) { return foo; } public Test1 delete(String arg1, String arg2) { System.out.println("Overloaded test 2 called"); return null; } } jpype-1.3.0/test/harness/jpype/attr/TestOverloadA.java000066400000000000000000000015131405671516700227600ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.attr; public class TestOverloadA { public String foo() { return "foo() in A"; } } jpype-1.3.0/test/harness/jpype/attr/TestOverloadB.java000066400000000000000000000014511405671516700227620ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.attr; public class TestOverloadB extends TestOverloadA { } jpype-1.3.0/test/harness/jpype/attr/TestOverloadC.java000066400000000000000000000015571405671516700227720ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.attr; public class TestOverloadC extends TestOverloadB { public String foo(int i) { return "foo(int) in C: " + i; } } jpype-1.3.0/test/harness/jpype/boxed/000077500000000000000000000000001405671516700175305ustar00rootroot00000000000000jpype-1.3.0/test/harness/jpype/boxed/Boxed.java000066400000000000000000000044111405671516700214340ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.boxed; public class Boxed { // Call each type static public boolean callBoolean(boolean i) { return i; } static public byte callByte(byte i) { return i; } static public char callChar(char i) { return i; } static public short callShort(short i) { return i; } static public int callInteger(int i) { return i; } static public long callLong(long i) { return i; } static public float callFloat(float i) { return i; } static public double callDouble(double i) { return i; } // Create a boxed type static public Short newShort(short i) { return i; } static public Integer newInteger(int i) { return i; } static public Long newLong(long i) { return i; } static public Float newFloat(float i) { return i; } static public Double newDouble(double i) { return i; } // Check which is called static public int whichShort(short i) { return 1; } static public int whichShort(Short i) { return 2; } static public int whichInteger(int i) { return 1; } static public int whichInteger(Integer i) { return 2; } static public int whichLong(long i) { return 1; } static public int whichLong(Long i) { return 2; } static public int whichFloat(float i) { return 1; } static public int whichFloat(Float i) { return 2; } static public int whichDouble(double i) { return 1; } static public int whichDouble(Double i) { return 2; } } jpype-1.3.0/test/harness/jpype/classhints/000077500000000000000000000000001405671516700206025ustar00rootroot00000000000000jpype-1.3.0/test/harness/jpype/classhints/ClassHintsTest.java000066400000000000000000000015741405671516700243670ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.classhints; public class ClassHintsTest { public static Custom input = null; public static void call(Custom c) { input = c; } } jpype-1.3.0/test/harness/jpype/classhints/Custom.java000066400000000000000000000014301405671516700227150ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.classhints; public interface Custom { } jpype-1.3.0/test/harness/jpype/closeable/000077500000000000000000000000001405671516700203605ustar00rootroot00000000000000jpype-1.3.0/test/harness/jpype/closeable/CloseableTest.java000066400000000000000000000026501405671516700237570ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.closeable; class CloseableTest implements java.io.Closeable { public static boolean closed = false; public static String printed = ""; public static boolean willfail = false; public static boolean failed = false; public static void reset() { closed = false; willfail = false; failed = false; printed = ""; } public CloseableTest() { } public void print(String value) { printed = value; } public void throwException() { throw new RuntimeException("oh no!"); } public void close() throws java.io.IOException { closed = true; if (willfail) { failed = true; throw new java.io.IOException("oh my?"); } } } jpype-1.3.0/test/harness/jpype/collection/000077500000000000000000000000001405671516700205625ustar00rootroot00000000000000jpype-1.3.0/test/harness/jpype/collection/CollectionTest.java000066400000000000000000000020661405671516700243640ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.collection; import java.util.Collection; import java.util.Map; public class CollectionTest { public static Object testList(Collection input) { System.out.println(input); return input; } public static Object testMap(Map input) { System.out.println(input); return input; } } jpype-1.3.0/test/harness/jpype/collection/TestEnum.java000066400000000000000000000014231405671516700231710ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.collection; enum TestEnum { A, B } jpype-1.3.0/test/harness/jpype/common/000077500000000000000000000000001405671516700177175ustar00rootroot00000000000000jpype-1.3.0/test/harness/jpype/common/Fixture.java000066400000000000000000000204521405671516700222130ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.common; public class Fixture { // Tests for access private static Object static_private_object_field = new String("private static object field"); private Object private_object_field = new String("private object field"); public final static Object final_static_object_field = new String("final static object field"); public final Object final_object_field = new String("final object field"); public final static int final_static_int_field = 12345; public final int final_int_field = 67890; public static boolean static_bool_field; public static char static_char_field; public static byte static_byte_field; public static short static_short_field; public static int static_int_field; public static long static_long_field; public static float static_float_field; public static double static_double_field; public static Object static_object_field; public static boolean getStaticBool() { return static_bool_field; } public static char getStaticChar() { return static_char_field; } public static byte getStaticByte() { return static_byte_field; } public static short getStaticShort() { return static_short_field; } public static int getStaticInt() { return static_int_field; } public static long getStaticLong() { return static_long_field; } public static float getStaticFloat() { return static_float_field; } public static double getStaticDouble() { return static_double_field; } public static Object getStaticObject() { return static_object_field; } public static void setStaticBool(boolean i) { static_bool_field = i; } public static void setStaticChar(char i) { static_char_field = i; } public static void setStaticByte(byte i) { static_byte_field = i; } public static void setStaticShort(short i) { static_short_field = i; } public static void setStaticInt(int i) { static_int_field = i; } public static void setStaticLong(long i) { static_long_field = i; } public static void setStaticFloat(float i) { static_float_field = i; } public static void setStaticDouble(double i) { static_double_field = i; } public static void setStaticObject(Object i) { static_object_field = i; } public boolean bool_field; public char char_field; public byte byte_field; public short short_field; public int int_field; public long long_field; public float float_field; public double double_field; public Object object_field; public boolean getBool() { return bool_field; } public char getChar() { return char_field; } public byte getByte() { return byte_field; } public short getShort() { return short_field; } public int getInt() { return int_field; } public long getLong() { return long_field; } public float getFloat() { return float_field; } public double getDouble() { return double_field; } public Object getObject() { return object_field; } public void setBool(boolean i) { bool_field = i; } public void setChar(char i) { char_field = i; } public void setByte(byte i) { byte_field = i; } public void setShort(short i) { short_field = i; } public void setInt(int i) { int_field = i; } public void setLong(long i) { long_field = i; } public void setFloat(float i) { float_field = i; } public void setDouble(double i) { double_field = i; } public void setObject(Object i) { object_field = i; } public static boolean throwStaticBool() { throw new RuntimeException("bool"); } public static char throwStaticChar() { throw new RuntimeException("char"); } public static byte throwStaticByte() { throw new RuntimeException("byte"); } public static short throwStaticShort() { throw new RuntimeException("short"); } public static int throwStaticInt() { throw new RuntimeException("int"); } public static long throwStaticLong() { throw new RuntimeException("long"); } public static float throwStaticFloat() { throw new RuntimeException("float"); } public static double throwStaticDouble() { throw new RuntimeException("double"); } public static Object throwStaticObject() { throw new RuntimeException("object"); } public boolean throwBool() { throw new RuntimeException("bool"); } public char throwChar() { throw new RuntimeException("char"); } public byte throwByte() { throw new RuntimeException("byte"); } public short throwShort() { throw new RuntimeException("short"); } public int throwInt() { throw new RuntimeException("int"); } public long throwLong() { throw new RuntimeException("long"); } public float throwFloat() { throw new RuntimeException("float"); } public double throwDouble() { throw new RuntimeException("double"); } public Object throwObject() { throw new RuntimeException("object"); } public boolean callBoolean(boolean i) { return i; } public byte callByte(byte i) { return i; } public char callChar(char i) { return i; } public short callShort(short i) { return i; } public int callInt(int i) { return i; } public long callLong(long i) { return i; } public float callFloat(float i) { return i; } public double callDouble(double i) { return i; } public String callString(String i) { return i; } public java.lang.Boolean callBoxedBoolean(java.lang.Boolean i) { return i; } public java.lang.Byte callBoxedByte(java.lang.Byte i) { return i; } public java.lang.Character callBoxedChar(java.lang.Character i) { return i; } public java.lang.Short callBoxedShort(java.lang.Short i) { return i; } public java.lang.Integer callBoxedInt(java.lang.Integer i) { return i; } public java.lang.Long callBoxedLong(java.lang.Long i) { return i; } public java.lang.Float callBoxedFloat(java.lang.Float i) { return i; } public java.lang.Double callBoxedDouble(java.lang.Double i) { return i; } public static boolean callStaticBoolean(boolean i) { return i; } public static byte callStaticByte(byte i) { return i; } public static char callStaticChar(char i) { return i; } public static short callStaticShort(short i) { return i; } public static int callStaticInt(int i) { return i; } public static long callStaticLong(long i) { return i; } public static float callStaticFloat(float i) { return i; } public static double callStaticDouble(double i) { return i; } public static String callStaticString(String i) { return i; } public static Object callStaticObject(Object i) { return i; } private static Object callPrivateStaticObject(Object i) { return i; } public Object callObject(Object i) { return i; } private Object callPrivateObject(Object i) { return i; } protected Object callProtectedObject(Object i) { return i; } public static Number callNumber(Number n) { return n; } public Object callSupplier(java.util.function.Supplier s) { return s.get(); } public Object callCharArray(char[] c) { return c; } public Object callByteArray(byte[] c) { return c; } public Object callClass(Class c) { return c; } public Iterable callIterable(Iterable c) { return c; } } jpype-1.3.0/test/harness/jpype/common/OnShutdown.java000066400000000000000000000041431405671516700226740ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.common; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * * @author nelson85 */ public class OnShutdown { static public void addCoverageHook(Object context) { try { Method method = context.getClass().getMethod("_addPost", Runnable.class); method.invoke(context, new CoverageHook()); } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { System.out.println("Fail to install post hook " + ex.getMessage()); } } private static class CoverageHook implements Runnable { @Override public void run() { // If coverage tools are being used, we need to dump last before everything // shuts down try { Class RT = Class.forName("org.jacoco.agent.rt.RT"); Method getAgent = RT.getMethod("getAgent"); Object agent = getAgent.invoke(null); Thread.sleep(100); // make sure we don't clober agent.getClass().getMethod("dump", boolean.class).invoke(agent, false); System.err.println("*** Coverage dumped"); } catch (InterruptedException | NullPointerException | ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { } } } } jpype-1.3.0/test/harness/jpype/doc/000077500000000000000000000000001405671516700171745ustar00rootroot00000000000000jpype-1.3.0/test/harness/jpype/doc/Test.java000066400000000000000000000030431405671516700207560ustar00rootroot00000000000000/* * Attempt at javadoc coverage test. */ package jpype.doc; /** * A bunch of random stuff. * * @author nelson85 * @see "The Java Programming Language" * @see java.lang.Object#wait() * @see Java Spec * @version 1.0 */ public class Test { public final static int QQ = 1; /** * This does something special. *

* It is so special we won't tell you. *
* We have our reasons. See a or *

a
. So up and don't look down. Literally * {@literal AC}. Don't feel s when you can be bold * or em or italics. *

* Use the {@link #methodOne(int, Object) BangBang} method. *. *

{@code
   *    hey.method(1, SecretMap());
   * }
*

* * * * *
NorthEastSteps
YN10
NY20
*

*

*
Defines *
Something. *
*
*
    *
  1. Item 1 *
      *
    • Apples *
    • Pears *
    *
  2. Item 2 *
* * @throws java.lang.NoSuchMethodException if something bad happens. * @param i an argument a. {@value #QQ} * @param j * @return a secret code. * @since 1.5 * */ public int methodOne(int i, Object j) throws NoSuchMethodException { return 12345; // Same as your luggage combination. } } jpype-1.3.0/test/harness/jpype/exc/000077500000000000000000000000001405671516700172065ustar00rootroot00000000000000jpype-1.3.0/test/harness/jpype/exc/ChildTestException.java000066400000000000000000000014631405671516700236170ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.exc; public class ChildTestException extends ParentTestException { } jpype-1.3.0/test/harness/jpype/exc/ExceptionTest.java000066400000000000000000000031621405671516700226510ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.exc; public class ExceptionTest { public static void throwRuntime() { throw new RuntimeException("Foo"); } public static void throwIOException() throws java.io.IOException { throw new java.io.IOException("Bar"); } public static boolean delegateThrow(ExceptionThrower th) { try { th.throwIOException(); } catch (java.io.IOException ex) { return true; } catch (Throwable ex) { System.out.println("Unexpected Exception during delegateThrow"); ex.printStackTrace(); } System.out.println("Failed"); return false; } public static void throwChildTestException() throws ParentTestException { throw new ChildTestException(); } public static void throwChain() { method1(); } static void method1() { method2(); } static void method2() { throw new RuntimeException("Inner"); } } jpype-1.3.0/test/harness/jpype/exc/ExceptionThrower.java000066400000000000000000000015111405671516700233600ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.exc; interface ExceptionThrower { void throwIOException() throws java.io.IOException; } jpype-1.3.0/test/harness/jpype/exc/ParentTestException.java000066400000000000000000000014641405671516700240260ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.exc; public class ParentTestException extends java.lang.Exception { } jpype-1.3.0/test/harness/jpype/exc/WierdException.java000066400000000000000000000017501405671516700230050ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.exc; public class WierdException extends Exception { public WierdException(int i, float f, Object o) { super("Got it"); } public static void testThrow() throws WierdException { throw new WierdException(1, 2, new Object()); } } jpype-1.3.0/test/harness/jpype/mro/000077500000000000000000000000001405671516700172245ustar00rootroot00000000000000jpype-1.3.0/test/harness/jpype/mro/A.java000066400000000000000000000014371405671516700202540ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.mro; interface A extends E, F { void foo(); } jpype-1.3.0/test/harness/jpype/mro/B.java000066400000000000000000000014201405671516700202450ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.mro; interface B extends D, A { } jpype-1.3.0/test/harness/jpype/mro/C.java000066400000000000000000000014631405671516700202550ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.mro; public class C implements A, B { public void foo() { } } jpype-1.3.0/test/harness/jpype/mro/D.java000066400000000000000000000014031405671516700202500ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.mro; interface D { } jpype-1.3.0/test/harness/jpype/mro/E.java000066400000000000000000000014031405671516700202510ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.mro; interface E { } jpype-1.3.0/test/harness/jpype/mro/F.java000066400000000000000000000014031405671516700202520ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.mro; interface F { } jpype-1.3.0/test/harness/jpype/mro/MultipleInterfaces.java000066400000000000000000000017261405671516700236740ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.mro; interface IA { } interface IB { } interface ICombined1 extends IA, IB { } interface ICombined2 extends IB, IA { } public class MultipleInterfaces implements ICombined1, ICombined2 { public MultipleInterfaces() { } } jpype-1.3.0/test/harness/jpype/numeric/000077500000000000000000000000001405671516700200715ustar00rootroot00000000000000jpype-1.3.0/test/harness/jpype/numeric/NumericTest.java000066400000000000000000000015761405671516700232070ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.numeric; public class NumericTest { public static boolean doubleIsTwiceMaxFloat(double d) { return d == (Float.MAX_VALUE * 2.0); } } jpype-1.3.0/test/harness/jpype/objectwrapper/000077500000000000000000000000001405671516700212765ustar00rootroot00000000000000jpype-1.3.0/test/harness/jpype/objectwrapper/Static.java000066400000000000000000000015651405671516700233770ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.objectwrapper; class StaticTest { public static int i = 1; public static double d = 1.2345; public static String s = "hello"; } jpype-1.3.0/test/harness/jpype/objectwrapper/Test1.java000066400000000000000000000021061405671516700231400ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.objectwrapper; public class Test1 { public Test1() { } public int Method1(Number n) { return 1; } public int Method1(Integer n) { return 2; } public int Method1(Object n) { return 3; } public int Method1(String n) { return 4; } public Object ReturnObject(Object o) { return o; } } jpype-1.3.0/test/harness/jpype/overloads/000077500000000000000000000000001405671516700204255ustar00rootroot00000000000000jpype-1.3.0/test/harness/jpype/overloads/Test1.java000066400000000000000000000130531405671516700222720ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.overloads; import java.util.List; public class Test1 { public static class A { } public static class B extends A { } public static class C extends B { } public String testMostSpecific(A a) { return "A"; } public String testMostSpecific(B b) { return "B"; } public String testVarArgs(A a, A... as) { return "A,A..."; } public String testVarArgs(A a, B... bs) { return "A,B..."; } public String testVarArgs(B a, B... bs) { return "B,B..."; } public String testPrimitive(byte v) { return "byte"; } public String testPrimitive(Byte v) { return "Byte"; } public String testPrimitive(short v) { return "short"; } public String testPrimitive(Short v) { return "Short"; } public String testPrimitive(int v) { return "int"; } public String testPrimitive(Integer v) { return "Integer"; } public String testPrimitive(long v) { return "long"; } public String testPrimitive(Long v) { return "Long"; } public String testPrimitive(float v) { return "float"; } public String testPrimitive(Float v) { return "Float"; } public String testPrimitive(double v) { return "double"; } public String testPrimitive(Double v) { return "Double"; } public String testPrimitive(boolean v) { return "boolean"; } public String testPrimitive(Boolean v) { return "Boolean"; } public String testPrimitive(char v) { return "char"; } public String testPrimitive(Character v) { return "Character"; } public static String testInstanceVsClass(B b) { return "static B"; } public String testInstanceVsClass(A a) { return "instance A"; } public static String testJavaInstanceVsClass() { return new Test1().testInstanceVsClass(new C()); } /* I1 / \ I2 I3 \ / \ I4 I5 | \ | I6 I7 \ | I8 */ public static interface I1 { } public static interface I2 extends I1 { } public static interface I3 extends I1 { } public static interface I4 extends I2, I3 { } public static interface I5 extends I3 { } public static interface I6 extends I4 { } public static interface I7 extends I4, I5 { } public static interface I8 extends I6, I7 { } public static class I1Impl implements I1 { } public static class I2Impl implements I2 { } public static class I3Impl implements I3 { } public static class I4Impl implements I4 { } public static class I5Impl implements I5 { } public static class I6Impl implements I6 { } public static class I7Impl implements I7 { } public static class I8Impl implements I8 { } public String testInterfaces1(I2 v) { return "I2"; } public String testInterfaces1(I3 v) { return "I3"; } public String testInterfaces2(I2 v) { return "I2"; } public String testInterfaces2(I3 v) { return "I3"; } public String testInterfaces2(I4 v) { return "I4"; } public String testInterfaces3(I4 v) { return "I4"; } public String testInterfaces3(I5 v) { return "I5"; } public String testInterfaces4(I1 v) { return "I1"; } public String testInterfaces4(I2 v) { return "I2"; } public String testInterfaces4(I3 v) { return "I3"; } public String testInterfaces4(I4 v) { return "I4"; } public String testInterfaces4(I5 v) { return "I5"; } public String testInterfaces4(I6 v) { return "I6"; } public String testInterfaces4(I7 v) { return "I7"; } public String testInterfaces4(I8 v) { return "I8"; } public String testClassVsObject(Object v) { return "Object"; } public String testClassVsObject(Class v) { return "Class"; } public String testStringArray(Object v) { return "Object"; } public String testStringArray(String v) { return "String"; } public String testStringArray(String[] v) { return "String[]"; } public String testListVSArray(String[] v) { return "String[]"; } public String testListVSArray(List v) { return "List"; } /* tests for java 1.8 default methods, commented out for travis environment public interface IDefaultA { public default String defaultMethod() { return "A"; } } public interface IDefaultB extends IDefaultA { public default String defaultMethod() { return "B"; } } public interface IDefaultC extends IDefaultA, IDefaultB { } public static class DefaultC implements IDefaultC { } //*/ } jpype-1.3.0/test/harness/jpype/override/000077500000000000000000000000001405671516700202465ustar00rootroot00000000000000jpype-1.3.0/test/harness/jpype/override/A.java000066400000000000000000000015001405671516700212650ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.override; public class A { public int remove(Object o) { return 1; } } jpype-1.3.0/test/harness/jpype/override/B.java000066400000000000000000000015121405671516700212710ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.override; public class B extends A { public int remove(Object o) { return 2; } } jpype-1.3.0/test/harness/jpype/properties/000077500000000000000000000000001405671516700206235ustar00rootroot00000000000000jpype-1.3.0/test/harness/jpype/properties/TestBean.java000066400000000000000000000055361405671516700232040ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.properties; public class TestBean { private String getA; private String setA; private String property1; private String property2Invisible; private String property3; public String property4; private String property5; private String property6; public String property7; public String getProperty1() { return "get" + property1; } public String getProperty2() { return "get" + property2Invisible; } public String getProperty3() { return "get" + property3; } public String abcProperty4() { return "abc" + property4; } public String getProperty6() { return "get" + property7; } public String property1() { return "method"; } protected String property2() { return "method"; } protected String property3() { return "method"; } public String returnProperty5() { return "return" + this.property5; } public void setProperty1(String property1) { this.property1 = "set" + property1; } public void setProperty2(String property2) { this.property2Invisible = "set" + property2; } public void setProperty3(String property3) { this.property3 = "set" + property3; } public void setProperty5(String property5) { this.property5 = "set" + property5; } public void setProperty6(String property6) { this.property7 = "set" + property6; } public static String m1; public String m2; public String m3; public String m4; public String m5; public String getPropertyMember() { return this.m2; } public void setPropertyMember(String value) { this.m2 = value; } public static String getPropertyStatic() { return m1; } public static void setPropertyStatic(String value) { m1 = value; } public String getReadOnly() { return this.m3; } public void setWriteOnly(String value) { this.m4 = value; } public void setWith(String value) { this.m5 = value; } public String getWith() { return this.m5; } public void setFailure1(String value, int i) { } public String getFailure2(int i) { return "fail"; } } jpype-1.3.0/test/harness/jpype/proxy/000077500000000000000000000000001405671516700176105ustar00rootroot00000000000000jpype-1.3.0/test/harness/jpype/proxy/ProxyExecutor.java000066400000000000000000000067421405671516700233240ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.proxy; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; public class ProxyExecutor { private ExecutorService executor; private List> executedTasks = new ArrayList>(); private List proxies = new ArrayList(); public ProxyExecutor(int noOfThreads) { executor = Executors.newFixedThreadPool(noOfThreads); } public void shutdown() { executor.shutdown(); // Disable new tasks from being submitted try { // Wait a while for existing tasks to terminate if (!executor.awaitTermination(5, TimeUnit.SECONDS)) { executor.shutdownNow(); // Cancel currently executing tasks // Wait a while for tasks to respond to being cancelled if (!executor.awaitTermination(5, TimeUnit.SECONDS)) System.err.println("Pool did not terminate"); } } catch (InterruptedException ie) { // (Re-)Cancel if current thread also interrupted executor.shutdownNow(); // Preserve interrupt status Thread.currentThread().interrupt(); } } public void registerProxy(TestInterface4 proxy, int noOfExecutions) { for (int i = 0; i < noOfExecutions; i++) { proxies.add(new ProxyCaller(proxy)); } } public int getExpectedTasks() { return proxies.size(); } public void runExecutor() { // Collections.shuffle(proxies); for (ProxyCaller proxy : proxies) { Future future = executor.submit(proxy); executedTasks.add(future); } } public int waitForExecutedTasks() { int returns = 0; for (Future task : executedTasks) { try { returns += task.get(); } catch (Exception ex) { System.out.println("An exception has thrown during execution"); ex.printStackTrace(); } } return returns; } public class ProxyCaller implements Callable { private TestInterface4 proxy; public ProxyCaller(TestInterface4 proxy) { this.proxy = proxy; } @Override public Integer call() throws Exception { int result = 0; try { int intValue = proxy.testMethodInt(); ReturnObject objectValue = proxy.testMethodObject(); String stringValue = proxy.testMethodString(); List listValue = proxy.testMethodList(5); } catch (Exception ex) { ex.printStackTrace(); } return 1; //result; } } } jpype-1.3.0/test/harness/jpype/proxy/ProxyTriggers.java000066400000000000000000000041521405671516700233050ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.proxy; import java.util.LinkedList; import java.util.List; public class ProxyTriggers { public static String[] testProxy(Object itf) { List methods = new LinkedList<>(); if (itf instanceof TestInterface1) { methods.add("Test Method1 = " + ((TestInterface1) itf).testMethod1()); } if (itf instanceof TestInterface2) { methods.add("Test Method2 = " + ((TestInterface2) itf).testMethod2()); } if (itf instanceof TestInterface3) { methods.add("Test Method3 = " + ((TestInterface3) itf).testMethod3()); } return methods.toArray(new String[0]); } public void testProxyWithThread(final TestThreadCallback itf) { itf.notifyValue("Waiting for thread start"); Thread t = new Thread(new Runnable() { public void run() { for (int i = 1; i <= 3; i++) { itf.notifyValue(String.valueOf(i)); } } }); t.start(); try { t.join(); itf.notifyValue("Thread finished"); } catch (InterruptedException ex) { Thread.currentThread().interrupt(); itf.notifyValue("Thread has been interrupted"); } } public Object[] testCallbackWithParameters(TestInterface2 itf) { byte[] vals = { 1, 2, 3, 4 }; return itf.write(vals, 12, 13); } public boolean testEquals(Object o) { return o.equals(o); } } jpype-1.3.0/test/harness/jpype/proxy/ReturnObject.java000066400000000000000000000016451405671516700230670ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.proxy; public class ReturnObject { private int number; public ReturnObject(int number) { this.number = number; } public int getNumber() { return number; } } jpype-1.3.0/test/harness/jpype/proxy/TestInterface1.java000066400000000000000000000014571405671516700233030ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.proxy; public interface TestInterface1 { int testMethod1(); } jpype-1.3.0/test/harness/jpype/proxy/TestInterface2.java000066400000000000000000000015461405671516700233030ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.proxy; public interface TestInterface2 { int testMethod2(); Object[] write(byte[] bytes, int pos, int length); } jpype-1.3.0/test/harness/jpype/proxy/TestInterface3.java000066400000000000000000000015111405671516700232740ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.proxy; public interface TestInterface3 extends TestInterface2 { String testMethod3(); } jpype-1.3.0/test/harness/jpype/proxy/TestInterface4.java000066400000000000000000000017011405671516700232760ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.proxy; import java.util.List; public interface TestInterface4 { ReturnObject testMethodObject(); int testMethodInt(); String testMethodString(); List testMethodList(int noOfValues); } jpype-1.3.0/test/harness/jpype/proxy/TestInterface5.java000066400000000000000000000014751405671516700233070ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.proxy; public interface TestInterface5 { public boolean equals(Object o); } jpype-1.3.0/test/harness/jpype/proxy/TestThreadCallback.java000066400000000000000000000015071405671516700241420ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.proxy; public interface TestThreadCallback { public void notifyValue(String step); } jpype-1.3.0/test/harness/jpype/reflect/000077500000000000000000000000001405671516700200535ustar00rootroot00000000000000jpype-1.3.0/test/harness/jpype/reflect/Annotation.java000066400000000000000000000020421405671516700230260ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.reflect; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(value = { ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) public @interface Annotation { public String value(); } jpype-1.3.0/test/harness/jpype/reflect/ReflectionTest.java000066400000000000000000000021201405671516700236430ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.reflect; public class ReflectionTest { public String publicField = "public"; private String privateField = "private"; public ReflectionTest() { } public String publicMethod() { return "public"; } private String privateMethod() { return "private"; } @Annotation("annotation") public void annotatedMethod() { } } jpype-1.3.0/test/harness/jpype/serial/000077500000000000000000000000001405671516700177065ustar00rootroot00000000000000jpype-1.3.0/test/harness/jpype/serial/SerializationTest.java000066400000000000000000000014721405671516700242320ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.serial; public class SerializationTest implements java.io.Serializable { } jpype-1.3.0/test/harness/jpype/str/000077500000000000000000000000001405671516700172375ustar00rootroot00000000000000jpype-1.3.0/test/harness/jpype/str/StringFunction.java000066400000000000000000000014701405671516700230600ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.str; public interface StringFunction { public String call(String s); } jpype-1.3.0/test/harness/jpype/str/Test.java000066400000000000000000000022671405671516700210300ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.str; public class Test { public static String staticField = "staticField"; public String memberField = "memberField"; public static String staticCall() { return "staticCall"; } public String memberCall() { return "memberCall"; } public static final String array[] = { "apples", "banana", "cherries", "dates", "elderberry" }; public static String callProxy(StringFunction f, String s) { return f.call(s); } } jpype-1.3.0/test/harness/jpype/types/000077500000000000000000000000001405671516700175735ustar00rootroot00000000000000jpype-1.3.0/test/harness/jpype/types/InnerTest.java000066400000000000000000000015171405671516700223550ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.types; public class InnerTest { public Object test() { return new Outer.Inner(); } } jpype-1.3.0/test/harness/jpype/types/Outer.java000066400000000000000000000016111405671516700215330ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.types; public interface Outer { Object get(); public class Inner implements Outer { public Object get() { return null; } } } jpype-1.3.0/test/harness/jpype/types/VirtualTest.java000077500000000000000000000235011405671516700227300ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.types; public class VirtualTest { public interface ObjectSupplier { Object get(); } public static class ClassObjectSupplier implements ObjectSupplier { public Object get() { return "implements"; } } public static class ClassObjectSupplier2 extends ClassObjectSupplier { public Object get() { return "extends"; } } public static ObjectSupplier getObjectImplements() { return new ClassObjectSupplier(); } public static ObjectSupplier getObjectExtends() { return new ClassObjectSupplier2(); } public static ObjectSupplier getObjectAnon() { return new ObjectSupplier() { public Object get() { return "anon"; } }; } public static ObjectSupplier getObjectAnonExtends() { return new ClassObjectSupplier() { public Object get() { return "anon-override"; } }; } // This one has to wait for us to abandon Java 7 // public static ObjectSupplier getLambda() // { // return () -> "lambda"; // } // public interface IntegerSupplier { int get(); } public static class ClassIntegerSupplier implements IntegerSupplier { public int get() { return 1; } } public static class ClassIntegerSupplier2 extends ClassIntegerSupplier { public int get() { return 2; } } public static IntegerSupplier getIntegerImplements() { return new ClassIntegerSupplier(); } public static IntegerSupplier getIntegerExtends() { return new ClassIntegerSupplier2(); } public static IntegerSupplier getIntegerAnon() { return new IntegerSupplier() { public int get() { return 3; } }; } public static IntegerSupplier getIntegerAnonExtends() { return new ClassIntegerSupplier() { public int get() { return 4; } }; } // // public interface ShortSupplier { short get(); } public static class ClassShortSupplier implements ShortSupplier { public short get() { return 1; } } public static class ClassShortSupplier2 extends ClassShortSupplier { public short get() { return 2; } } public static ShortSupplier getShortImplements() { return new ClassShortSupplier(); } public static ShortSupplier getShortExtends() { return new ClassShortSupplier2(); } public static ShortSupplier getShortAnon() { return new ShortSupplier() { public short get() { return 3; } }; } public static ShortSupplier getShortAnonExtends() { return new ClassShortSupplier() { public short get() { return 4; } }; } // // public interface LongSupplier { long get(); } public static class ClassLongSupplier implements LongSupplier { public long get() { return 1; } } public static class ClassLongSupplier2 extends ClassLongSupplier { public long get() { return 2; } } public static LongSupplier getLongImplements() { return new ClassLongSupplier(); } public static LongSupplier getLongExtends() { return new ClassLongSupplier2(); } public static LongSupplier getLongAnon() { return new LongSupplier() { public long get() { return 3; } }; } public static LongSupplier getLongAnonExtends() { return new ClassLongSupplier() { public long get() { return 4; } }; } // // public interface FloatSupplier { float get(); } public static class ClassFloatSupplier implements FloatSupplier { public float get() { return 1; } } public static class ClassFloatSupplier2 extends ClassFloatSupplier { public float get() { return 2; } } public static FloatSupplier getFloatImplements() { return new ClassFloatSupplier(); } public static FloatSupplier getFloatExtends() { return new ClassFloatSupplier2(); } public static FloatSupplier getFloatAnon() { return new FloatSupplier() { public float get() { return 3; } }; } public static FloatSupplier getFloatAnonExtends() { return new ClassFloatSupplier() { public float get() { return 4; } }; } // // public interface DoubleSupplier { double get(); } public static class ClassDoubleSupplier implements DoubleSupplier { public double get() { return 1; } } public static class ClassDoubleSupplier2 extends ClassDoubleSupplier { public double get() { return 2; } } public static DoubleSupplier getDoubleImplements() { return new ClassDoubleSupplier(); } public static DoubleSupplier getDoubleExtends() { return new ClassDoubleSupplier2(); } public static DoubleSupplier getDoubleAnon() { return new DoubleSupplier() { public double get() { return 3; } }; } public static DoubleSupplier getDoubleAnonExtends() { return new ClassDoubleSupplier() { public double get() { return 4; } }; } // // public interface ByteSupplier { byte get(); } public static class ClassByteSupplier implements ByteSupplier { public byte get() { return 1; } } public static class ClassByteSupplier2 extends ClassByteSupplier { public byte get() { return 2; } } public static ByteSupplier getByteImplements() { return new ClassByteSupplier(); } public static ByteSupplier getByteExtends() { return new ClassByteSupplier2(); } public static ByteSupplier getByteAnon() { return new ByteSupplier() { public byte get() { return 3; } }; } public static ByteSupplier getByteAnonExtends() { return new ClassByteSupplier() { public byte get() { return 4; } }; } // // public interface CharSupplier { char get(); } public static class ClassCharSupplier implements CharSupplier { public char get() { return '1'; } } public static class ClassCharSupplier2 extends ClassCharSupplier { public char get() { return '2'; } } public static CharSupplier getCharImplements() { return new ClassCharSupplier(); } public static CharSupplier getCharExtends() { return new ClassCharSupplier2(); } public static CharSupplier getCharAnon() { return new CharSupplier() { public char get() { return '3'; } }; } public static CharSupplier getCharAnonExtends() { return new ClassCharSupplier() { public char get() { return '4'; } }; } // // public interface BooleanSupplier { boolean get(); } public static class ClassBooleanSupplier implements BooleanSupplier { public boolean get() { return true; } } public static class ClassBooleanSupplier2 extends ClassBooleanSupplier { public boolean get() { return false; } } public static BooleanSupplier getBooleanImplements() { return new ClassBooleanSupplier(); } public static BooleanSupplier getBooleanExtends() { return new ClassBooleanSupplier2(); } public static BooleanSupplier getBooleanAnon() { return new BooleanSupplier() { public boolean get() { return false; } }; } public static BooleanSupplier getBooleanAnonExtends() { return new ClassBooleanSupplier() { public boolean get() { return false; } }; } // // // Yes, we have to do this one as well. All paths need exercise. public interface VoidSupplier { void get(); } public static class ClassVoidSupplier implements VoidSupplier { public void get() { return; } } public static class ClassVoidSupplier2 extends ClassVoidSupplier { public void get() { return; } } public static VoidSupplier getVoidImplements() { return new ClassVoidSupplier(); } public static VoidSupplier getVoidExtends() { return new ClassVoidSupplier2(); } public static VoidSupplier getVoidAnon() { return new VoidSupplier() { public void get() { return; } }; } public static VoidSupplier getVoidAnonExtends() { return new ClassVoidSupplier() { public void get() { return; } }; } // } jpype-1.3.0/test/harness/jpype/utf8/000077500000000000000000000000001405671516700173155ustar00rootroot00000000000000jpype-1.3.0/test/harness/jpype/utf8/Utf8Test.java000066400000000000000000000115111405671516700216450ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.utf8; public class Utf8Test { private final static String[] DEFAULT_STRINGS = { "I can eat glass and it doesn't hurt me.", "Je peux manger du verre, \u00E7a ne me fait pas mal.", "\u16D6\u16B4 \u16B7\u16D6\u16CF \u16D6\u16CF\u16C1 \u16A7 \u16B7\u16DA\u16D6\u16B1 \u16D8\u16BE \u16A6\u16D6\u16CB\u16CB \u16A8\u16A7 \u16A1\u16D6 \u16B1\u16A7\u16A8 \u16CB\u16A8\u16B1", "\u4EBA\u4EBA\u751F\u800C\u81EA\u7531,\u5728\u5C0A\u4E25\u548C\u6743\u5229\u4E0A\u4E00\u5F8B\u5E73\u7B49\u3002\u4ED6\u4EEC\u8D4B\u6709\u7406\u6027\u548C\u826F\u5FC3,\u5E76\u5E94\u4EE5\u5144\u5F1F\u5173\u7CFB\u7684\u7CBE\u795E\u4E92\u76F8\u5BF9\u5F85\u3002", "\u4EBA\u4EBA\u751F\u800C\u81EA\u7531\uFE50\u5728\u5C0A\u56B4\u548C\u6B0A\u5229\u4E0A\u4E00\u5F8B\u5E73\u7B49\u3002\u4ED6\u5011\u8CE6\u6709\u7406\u6027\u548C\u826F\u5FC3\uFE50\u4E26\u61C9\u4EE5\u5144\u5F1F\u95DC\u4FC2\u7684\u7CBE\u795E\u4E92\u76F8\u5C0D\u5F85\u3002", "\u0623\u0646\u0627 \u0642\u0627\u062F\u0631 \u0639\u0644\u0649 \u0623\u0643\u0644 \u0627\u0644\u0632\u062C\u0627\u062C \u0648 \u0647\u0630\u0627 \u0644\u0627 \u064A\u0624\u0644\u0645\u0646\u064A.", "\uD83D\uDE01\uD83D\uDE02\uD83D\uDE03\uD83D\uDE04\uD83D\uDE05\uD83D\uDE06\uD83D\uDE20\uD83D\uDE21\uD83D\uDE22\uD83D\uDE23\uD83D\uDE24\uD83D\uDE25\uD83D\uDE28\uD83D\uDE29\uD83D\uDE2A\uD83D\uDE89\uD83D\uDE8C\uD83D\uDE8F\uD83D\uDE91\uD83D\uDE92\uD83D\uDE93\uD83D\uDE95\uD83D\uDE97\uD83D\uDE99\uD83D\uDE9A\uD83D\uDEA2\uD83D\uDEA4\uD83D\uDEA5\uD83D\uDEA7\uD83D\uDEA8\uD83D\uDEBB\uD83D\uDEBC\uD83D\uDEBD\uD83D\uDEBE\uD83D\uDEC0\uD83C\uDD95\uD83C\uDD96\uD83C\uDD97\uD83C\uDD98\uD83C\uDD99\uD83C\uDD9A\uD83C\uDE01\uD83C\uDE02\uD83C\uDE1A\uD83C\uDE2F\uD83C\uDE39\uD83C\uDE3A\uD83C\uDE50\uD83C\uDE518\u20E39\u20E37\u20E36\u20E31\u20E30" }; private String data; /** * Dummy: just set a pure ascii string */ public Utf8Test() { this.data = "Utf8Test pure ASCII"; } /** * Instantiate the class with one of the DEFAULT strings. Use the index as * reference. * * @param indx reference to the DEFAULT_STRING */ public Utf8Test(int indx) { this.data = DEFAULT_STRINGS[Math.abs(indx) % DEFAULT_STRINGS.length]; } /** * Instantiate with a user-defined string * * @param myinput */ public Utf8Test(String myinput) { if (null == myinput) { this.data = "NULL INPUT"; } else { try { int indx = Integer.parseInt(myinput); this.data = DEFAULT_STRINGS[Math.abs(indx) % DEFAULT_STRINGS.length]; } catch (NumberFormatException nfe) { this.data = myinput; } } } public void print_system_info() { System.out.println("----------------------------------------------------------------------------------------"); System.out.println("JVM: " + System.getProperty("java.vm.name") + ", version: " + System.getProperty("java.version") + " (" + System.getProperty("java.vm.version") + ")"); System.out.println("OS: " + System.getProperty("os.name") + "-" + System.getProperty("os.arch") + ", version: " + System.getProperty("os.version")); System.out.println("----------------------------------------------------------------------------------------"); } public void print_to_stdout() { int nc = (int) this.data.codePoints().count(); int nb = this.data.getBytes().length; System.out.println(String.format("nc = %3d, nb = %3d: (%s)", nc, nb, this.data)); } /* * get the string defined by the instantiator */ public String get() { return this.data; } /* * return true if the string defined by the instantiator equals the default string with given index */ public boolean equalsTo(int indx) { return DEFAULT_STRINGS[Math.abs(indx) % DEFAULT_STRINGS.length].equals(this.data); } public static void main(String[] argv) { Utf8Test jp; new Utf8Test().print_system_info(); if (0 == argv.length) { new Utf8Test().print_to_stdout(); for (int i = 0; i < DEFAULT_STRINGS.length; i++) { new Utf8Test(i).print_to_stdout(); } } else { new Utf8Test(argv[0]).print_to_stdout(); } } } jpype-1.3.0/test/harness/jpype/varargs/000077500000000000000000000000001405671516700200745ustar00rootroot00000000000000jpype-1.3.0/test/harness/jpype/varargs/VarArgs.java000066400000000000000000000046641405671516700223160ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package jpype.varargs; import java.util.Map; class VarArgs { public Object[] rest; public static Object[] call(Object... args) { return args; } public static String[] callString(String... args) { return args; } public static int callString0(String str, String... args) { return args.length; } public int callString1(String str, String... args) { return args.length; } public static Integer callOverload(Integer i) { return i; } public static String[] callOverload(String str, String... rest) { return rest; } public VarArgs() { } public VarArgs(String s, Object... rest) { this.rest = rest; } public String[] method(String s, String... rest) { return rest; } public int conflict1(Object... j) { return 1; } public int conflict1(Map j) { return 2; } public int conflict2(Object... j) { return 1; } public int conflict2(Map j, Map k) { return 2; } public int conflict3(char... j) { return 1; } public int conflict3(String j) { return 2; } // Conflict 4 - overloaded multi-param signature, vararg of identical type public int conflict4(Object o, double... j) { return 1; } public int conflict4(Object o, double j) { return 2; } // Conflict 5 - overloaded single-param signature, vararg of identical type // NB: pre-patch, conflict4 deterministically generated an ambiguous match error. // However, conflict5 would arbitrarily pick between these two signatures when // called with a single variable, resulting in unpredictable failures. public int conflict5(double... j) { return 1; } public int conflict5(double j) { return 2; } } jpype-1.3.0/test/harness/org/000077500000000000000000000000001405671516700160675ustar00rootroot00000000000000jpype-1.3.0/test/harness/org/jpype/000077500000000000000000000000001405671516700172165ustar00rootroot00000000000000jpype-1.3.0/test/harness/org/jpype/fail/000077500000000000000000000000001405671516700201315ustar00rootroot00000000000000jpype-1.3.0/test/harness/org/jpype/fail/BadInitializer.java000066400000000000000000000015221405671516700236660ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype.fail; public class BadInitializer { static { int[] i = new int[0]; i[1] = 2; } } jpype-1.3.0/test/harness/org/jpype/fail/BadInitializer2.java000066400000000000000000000017031405671516700237510ustar00rootroot00000000000000/* **************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See NOTICE file for details. **************************************************************************** */ package org.jpype.fail; // To test this with more than one path, we need a second // copy. Java caches the result of the first attempt public class BadInitializer2 { static { int[] i = new int[0]; i[1] = 2; } } jpype-1.3.0/test/jar/000077500000000000000000000000001405671516700144115ustar00rootroot00000000000000jpype-1.3.0/test/jar/README000066400000000000000000000002601405671516700152670ustar00rootroot00000000000000This directory contains special jars that were formulated to test different aspects of the import system. They were constructed using resource in the jpype/project directory. jpype-1.3.0/test/jar/late/000077500000000000000000000000001405671516700153365ustar00rootroot00000000000000jpype-1.3.0/test/jar/late/late.jar000066400000000000000000000017541405671516700167700ustar00rootroot00000000000000PK}Q META-INF/PKPK}QMETA-INF/MANIFEST.MFMLK-. K-*ϳR03r.JM,IMu E, 4BJJJ5yxPKP78PK }Qorg/PK }Q org/jpype/PK }Qorg/jpype/late/PK}Qorg/jpype/late/Test.classE?KAr=MLbee#I TlAZ$wxq B~(qvm7f{p.!8 1 On ޥ"8}]/Й6ˌYxKϵѤH_ҤLz= p,c7sli29ofJ{`t~PK>PK}Q META-INF/PK}QP78=META-INF/MANIFEST.MFPK }Qorg/PK }Q org/jpype/PK }Qorg/jpype/late/PK}Q>-org/jpype/late/Test.classPKkkjpype-1.3.0/test/jar/late/late2.jar000066400000000000000000000017601405671516700170470ustar00rootroot00000000000000PK}Q META-INF/PKPK}QMETA-INF/MANIFEST.MFMLK-. K-*ϳR03r.JM,IMu E, 4BJJJ5yxPKP78PK }Qorg/PK }Q org/jpype/PK }Qorg/jpype/late2/PK}Qorg/jpype/late2/Test.classEJ@ƿIMFk=ydۃ=*^A(=i׸!͖|+=E2̟'3F`ACBpd" A\FK?:Wz% jl.dȋ;b-̓fp4VSySfsӪ<'smZYqĪt% L]eVm7FfVJHE%G|tOΙ8\MAT{uǘ;C ײ]PK_?PK}Q META-INF/PK}QP78=META-INF/MANIFEST.MFPK }Qorg/PK }Q org/jpype/PK }Qorg/jpype/late2/PK}Q_?.org/jpype/late2/Test.classPKmmjpype-1.3.0/test/jar/missing.jar000066400000000000000000000010301405671516700165520ustar00rootroot00000000000000PK9QMETA-INF/MANIFEST.MFMLK-. K-*ϳR03r.JM,IMu E, 4BJJJ5yxPKP78PKQorg/jpype/missing/Test.class @EibD+; ;p [D &.aC^!YVG;3wȇ ElUX^}y *#Y"ʈcyPxlu*"aZ OG%yF L8G[a]Ir.Ct@ӀPK얫PK9QP78META-INF/MANIFEST.MFPKQ얫}org/jpype/missing/Test.classPKrjpype-1.3.0/test/jar/mrjar.jar000066400000000000000000000051231405671516700162230ustar00rootroot00000000000000PKazQ META-INF/PKPKazQMETA-INF/MANIFEST.MFMLK-. K-*ϳR03r.JM,IMu E, 4BJJJ5y|KsJ2uRsRSJJSyxPK/\LMPK azQorg/PK azQ org/jpype/PK azQorg/jpype/mrjar/PKazQorg/jpype/mrjar/A.class;o>c^.f.vnvF6̼;Ff 0FTF~̼TܤԢĤWp~iQr[&樗X _UPY[X IKOJM.aPd` @$ـl<5CpG՘`7kEhu+j4~@:PK-cPK azQorg/jpype/mrjar/sub/PKazQorg/jpype/mrjar/sub/C.class;o>c^.f.vnvF6̼;Ff 0FTF~̼TܤԢĤWp~iQr[&欗X _UPY[X_\ R\ Hy`>vƍ`iv d@PKqjPK azQMETA-INF/versions/9/PK azQMETA-INF/versions/9/org/PK azQMETA-INF/versions/9/org/jpype/PK azQ$META-INF/versions/9/org/jpype/mrjar/PKazQ+META-INF/versions/9/org/jpype/mrjar/B.class]jQϸfctba[ +zY?rYUR yJAp33os<S:w ] V~iV\j#edc2A8ONLXUF'_[Qw2 tKtQ"74bBbQ X\] P}Nܝ=Bս+ڻKX/٭3PKzYPKazQ META-INF/PKazQ/\LM=META-INF/MANIFEST.MFPK azQorg/PK azQ org/jpype/PK azQorg/jpype/mrjar/PKazQA§Corg/jpype/mrjar/A.classPKazQ-c/org/jpype/mrjar/B.classPK azQJorg/jpype/mrjar/sub/PKazQqj|org/jpype/mrjar/sub/C.classPK azQpMETA-INF/versions/9/PK azQMETA-INF/versions/9/org/PK azQMETA-INF/versions/9/org/jpype/PK azQ$META-INF/versions/9/org/jpype/mrjar/PKazQzY+VMETA-INF/versions/9/org/jpype/mrjar/B.classPKjpype-1.3.0/test/jar/unsatisfied.jar000066400000000000000000000021771405671516700174340ustar00rootroot00000000000000PKH7R META-INF/PKPKH7RMETA-INF/MANIFEST.MFMLK-. K-*ϳR03r.JM,IMu E, 4BJJJ5yxPKP78PK H7Rorg/PK H7R org/jpype/PK H7Rorg/jpype/unsatisfied/PKH7R%org/jpype/unsatisfied/TestClass.classmQNA=kYATdp K j`}YJ-4(]$)=ǹXӑG!(iаɐ8T' QvkmKGvOx]޳\: %=ܴ34;ʓΰ&VmFFѕs%;)BӝNBݨ]oh'dJhZ x}ђaծ,rNCCRVel3r ~kI]fy: X3i)n@dWjmf&gѲƲ]aqDB-du*t3W'z&f`(+HϩP|=E!P$ud:O){W:C6FPK^ '3': l = int(123) else: l = long(123) h.setByte(l) self.assertEqual(l, h.mByteValue) h.setShort(l) self.assertEqual(l, h.mShortValue) h.setInt(l) self.assertEqual(l, h.mIntValue) h.setLong(l) self.assertEqual(l, h.mLongValue) def testCallWithBigLong(self): h = JClass('jpype.attr.Test1')() if sys.version > '3': l = int(4398046511103) else: l = long(4398046511103) self.assertRaises(OverflowError, h.setByte, l) self.assertRaises(OverflowError, h.setShort, l) self.assertRaises(OverflowError, h.setInt, l) h.setLong(l) self.assertEqual(l, h.mLongValue) def testCallWithBigInt(self): h = JClass('jpype.attr.Test1')() if sys.version > '3' or sys.maxint > 2**31: l = int(4398046511103) else: l = long(4398046511103) self.assertRaises(OverflowError, h.setByte, l) self.assertRaises(OverflowError, h.setShort, l) self.assertRaises(OverflowError, h.setInt, l) h.setLong(l) self.assertEqual(l, h.mLongValue) def testSetBoolean(self): h = JClass('jpype.attr.Test1')() self.assertEqual(False, h.mBooleanValue) h.setBoolean(True) self.assertEqual(True, h.mBooleanValue) h.setBoolean(False) self.assertEqual(False, h.mBooleanValue) # just testing the status quo, not sure about if this is nice h.setBoolean(42) self.assertEqual(True, h.mBooleanValue) h.setBoolean(0) self.assertEqual(False, h.mBooleanValue) if sys.version > '3': l = int(4398046511103) else: l = long(4398046511103) h.setBoolean(l) self.assertEqual(True, h.mBooleanValue) if sys.version > '3': l = int(0) else: l = long(0) h.setBoolean(l) self.assertEqual(False, h.mBooleanValue) def testCreateDate(self): d = jpype.java.util.Date(1448799485000) self.assertEqual(1448799485000, d.getTime()) def testCharAttribute(self): h = JClass('jpype.attr.Test1')() h.charValue = u'b' self.assertEqual(h.charValue, 'b') if sys.version < '3': exp_repr = "u'b'" else: exp_repr = "'b'" self.assertEqual(repr(h.charValue), exp_repr) def testGetPrimitiveType(self): Integer = jpype.JClass("java.lang.Integer") intType = Integer.TYPE def testDifferentiateClassAndObject(self): h = JClass('jpype.attr.Test1')() self.assertEqual(h.callWithSomething( JClass('jpype.attr.Test1')), u"Class") result = h.callWithSomething(jpype.JObject(JClass('jpype.attr.Test1'), jpype.java.lang.Object)) self.assertEqual(result, u"Object") def testToString(self): h = JClass('jpype.attr.Test1')() self.assertEqual(str(h), 'aaa') def testSuperToString(self): h = JClass('jpype.attr.Test2')() self.assertEqual(str(h), 'aaa') # def testStringToConversion(self): # try: # jpype.ConversionConfig.string = False # for i in range(1): # h = JClass('jpype.attr.Test1')() # # start = time.time(); # for j in range(10): # ts = h.getBigString() # stop = time.time() # print ts.__class__, (stop-start), 'ms' # # # for comparison ... convert a string to JStrng and back # s = "".join([" "]*1024*1024*5) # start = time.time() # js = JString(s) # stop = time.time() # print "converted to JString in", (stop-start), 'ms', len(s) # # start = time.time() # cs = str(JString(s)) # print cs # print "converted to String in", (stop-start), 'ms', len(cs), cs # finally: # jpype.ConversionConfig.string = True def testComplexMethodOvlerloading(self): c = JClass('jpype.attr.TestOverloadC')() self.assertEqual(c.foo(1), "foo(int) in C: 1") self.assertEqual(c.foo(), "foo() in A") def testPassedObjectGetsCleanedUp(self): import platform if platform.python_implementation() == 'PyPy': raise common.unittest.SkipTest( 'PyPy memory model does not pass test') h = JClass('jpype.attr.Test1')() block_size = 1024 * 1024 * 10 def allocate_then_free(): byte_buffer = jpype.JClass('java.nio.ByteBuffer') inst = byte_buffer.allocate(1024 * 1024 * 100) # passing the object back to java seems to stop it being collected result = h.callWithSomething(inst) rt = jpype.java.lang.Runtime.getRuntime() free = rt.freeMemory() for x in range(0, 10 * free // block_size): allocate_then_free() def testSyntheticMethod(self): h = jpype.JClass('jpype.attr.SyntheticMethods$GenericImpl')() h.foo(jpype.java.util.ArrayList()) jpype-1.3.0/test/jpypetest/test_boxed.py000066400000000000000000000370621405671516700204060ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import sys import jpype import common from jpype.types import * from jpype import java def passThrough(item): al = JClass("java.util.ArrayList")() al.add(item) return al.get(0) class BoxedTestCase(common.JPypeTestCase): __name__ = "BoxedTestCase" def setUp(self): common.JPypeTestCase.setUp(self) self.TestBoxed = jpype.JClass('jpype.boxed.Boxed') self.Number = jpype.JClass('java.lang.Number') self.Comparable = jpype.JClass('java.lang.Comparable') def testShort(self): c1 = 12345 # Check passed from and passed to d1 = self.TestBoxed.newShort(c1) d2 = java.lang.Short(c1) self.assertEqual(d1, c1) self.assertEqual(d2, c1) self.assertEqual(c1, d1) self.assertEqual(c1, d2) self.assertEqual(d1, d2) self.assertEqual(self.TestBoxed.callShort(c1), self.TestBoxed.callShort(d2)) # Verify ops self.assertEqual(d1 + 2, d1 + 2) self.assertEqual(d1 * 2, d1 * 2) def testInteger(self): c1 = 12345 # Check passed from and passed to d1 = self.TestBoxed.newInteger(c1) d2 = java.lang.Integer(c1) self.assertEqual(d1, c1) self.assertEqual(d2, c1) self.assertEqual(c1, d1) self.assertEqual(c1, d2) self.assertEqual(d1, d2) self.assertEqual(self.TestBoxed.callInteger(c1), self.TestBoxed.callInteger(d2)) # Verify ops self.assertEqual(d1 + 2, d1 + 2) self.assertEqual(d1 * 2, d1 * 2) def testLong(self): c1 = 12345 # Check passed from and passed to d1 = self.TestBoxed.newLong(c1) d2 = java.lang.Long(c1) self.assertEqual(d1, c1) self.assertEqual(d2, c1) self.assertEqual(c1, d1) self.assertEqual(c1, d2) self.assertEqual(d1, d2) self.assertEqual(self.TestBoxed.callLong(c1), self.TestBoxed.callLong(d2)) # Verify ops self.assertEqual(d1 + 2, d1 + 2) self.assertEqual(d1 * 2, d1 * 2) def testDoubleFromFloat(self): java.lang.Double(1.0) def testFloatFromInt(self): java.lang.Float(1) def testDoubleFromInt(self): java.lang.Double(1) def testBoxed2(self): java.lang.Short(java.lang.Integer(1)) java.lang.Integer(java.lang.Integer(1)) java.lang.Long(java.lang.Integer(1)) java.lang.Float(java.lang.Integer(1)) java.lang.Float(java.lang.Long(1)) java.lang.Double(java.lang.Integer(1)) java.lang.Double(java.lang.Long(1)) java.lang.Double(java.lang.Float(1)) def testFloat(self): c1 = 123124 / 256.0 # Check passed from and passed to d1 = self.TestBoxed.newFloat(c1) d2 = java.lang.Float(c1) self.assertEqual(d1, c1) self.assertEqual(d2, c1) self.assertEqual(c1, d1) self.assertEqual(c1, d2) self.assertEqual(d1, d2) self.assertEqual(self.TestBoxed.callFloat(c1), self.TestBoxed.callFloat(d2)) # Verify ops self.assertEqual(d1 + 2, d1 + 2) self.assertEqual(d1 * 2, d1 * 2) self.assertTrue(d2 < c1 + 1) self.assertTrue(d2 > c1 - 1) def testDouble(self): c1 = 123124 / 256.0 # Check passed from and passed to d1 = self.TestBoxed.newDouble(c1) d2 = java.lang.Double(c1) self.assertEqual(d1, c1) self.assertEqual(d2, c1) self.assertEqual(c1, d1) self.assertEqual(c1, d2) self.assertEqual(d1, d2) self.assertEqual(self.TestBoxed.callDouble(c1), self.TestBoxed.callDouble(d2)) # Verify ops self.assertEqual(d1 + 2, d1 + 2) self.assertEqual(d1 * 2, d1 * 2) self.assertTrue(d2 < c1 + 1) self.assertTrue(d2 > c1 - 1) def testShortResolve(self): self.assertEqual(self.TestBoxed.whichShort(1), 1) self.assertEqual(self.TestBoxed.whichShort(java.lang.Short(1)), 2) def testIntegerResolve(self): self.assertEqual(self.TestBoxed.whichInteger(1), 1) self.assertEqual(self.TestBoxed.whichInteger(java.lang.Integer(1)), 2) def testLongResolve(self): self.assertEqual(self.TestBoxed.whichLong(1), 1) self.assertEqual(self.TestBoxed.whichLong(java.lang.Long(1)), 2) def testFloatResolve(self): self.assertEqual(self.TestBoxed.whichFloat(1.0), 1) self.assertEqual(self.TestBoxed.whichFloat(java.lang.Float(1.0)), 2) def testDoubleResolve(self): self.assertEqual(self.TestBoxed.whichDouble(1.0), 1) self.assertEqual(self.TestBoxed.whichDouble(java.lang.Double(1.0)), 2) def testPrivitiveToBoxed(self): java.lang.Boolean(JBoolean(0)) java.lang.Byte(JByte(0)) java.lang.Short(JShort(0)) java.lang.Integer(JInt(0)) java.lang.Long(JLong(0)) java.lang.Float(JFloat(0)) java.lang.Double(JDouble(0)) def testBooleanBad(self): # java.lang.Boolean(X) works like bool(X) # Explicit is a cast self.assertFalse(java.lang.Boolean(tuple())) self.assertFalse(java.lang.Boolean(list())) self.assertFalse(java.lang.Boolean(dict())) self.assertFalse(java.lang.Boolean(set())) self.assertTrue(java.lang.Boolean(tuple(['a']))) self.assertTrue(java.lang.Boolean(['a'])) self.assertTrue(java.lang.Boolean({'a': 1})) self.assertTrue(java.lang.Boolean(set(['a', 'b']))) # Implicit does not automatically cast fixture = JClass('jpype.common.Fixture')() with self.assertRaises(TypeError): fixture.callBoxedBoolean(tuple()) with self.assertRaises(TypeError): fixture.callBoxedBoolean(list()) with self.assertRaises(TypeError): fixture.callBoxedBoolean(dict()) with self.assertRaises(TypeError): fixture.callBoxedBoolean(set()) def testByteBad(self): with self.assertRaises(TypeError): java.lang.Byte(tuple()) def testCharacterBad(self): with self.assertRaises(TypeError): java.lang.Character(tuple()) def testShortBad(self): with self.assertRaises(TypeError): java.lang.Short(tuple()) def testIntegerBad(self): with self.assertRaises(TypeError): java.lang.Integer(tuple()) def testLongBad(self): with self.assertRaises(TypeError): java.lang.Long(tuple()) def testFloatBad(self): with self.assertRaises(TypeError): java.lang.Float(tuple()) def testDoubleBad(self): with self.assertRaises(TypeError): java.lang.Double(tuple()) def testBooleanBad2(self): with self.assertRaises(TypeError): java.lang.Boolean(tuple(), tuple()) def testByteBad2(self): with self.assertRaises(TypeError): java.lang.Byte(tuple(), tuple()) def testCharacterBad2(self): with self.assertRaises(TypeError): java.lang.Character(tuple(), tuple()) def testShortBad2(self): with self.assertRaises(TypeError): java.lang.Short(tuple(), tuple()) def testIntegerBad2(self): with self.assertRaises(TypeError): java.lang.Integer(tuple(), tuple()) def testLongBad2(self): with self.assertRaises(TypeError): java.lang.Long(tuple(), tuple()) def testFloatBad2(self): with self.assertRaises(TypeError): java.lang.Float(tuple(), tuple()) def testDoubleBad2(self): with self.assertRaises(TypeError): java.lang.Double(tuple(), tuple()) def compareTest(self, u, v): self.assertEqual(u, v) self.assertNotEqual(u, v - 1) self.assertTrue(u > v - 1) self.assertFalse(u > v + 1) self.assertTrue(u >= v) self.assertTrue(u <= v) self.assertFalse(u < v) self.assertFalse(u > v) self.assertTrue(u < v + 1) self.assertTrue(u > v - 1) def testByteBoxOps(self): u = JObject(81, JByte) self.assertIsInstance(u, jpype.java.lang.Byte) self.compareTest(u, 81) def testCharBoxOps(self): u = JObject('Q', JChar) self.assertIsInstance(u, jpype.java.lang.Character) self.compareTest(u, 81) def testShortBoxOps(self): u = JObject(81, JShort) self.assertIsInstance(u, jpype.java.lang.Short) self.compareTest(u, 81) def testIntBoxOps(self): u = JObject(81, JInt) self.assertIsInstance(u, jpype.java.lang.Integer) self.compareTest(u, 81) def testLongBoxOps(self): u = JObject(81, JLong) self.assertIsInstance(u, jpype.java.lang.Long) self.compareTest(u, 81) def testIntBoxOps(self): u = JObject(81, JFloat) self.assertIsInstance(u, jpype.java.lang.Float) self.compareTest(u, 81) def testLongBoxOps(self): u = JObject(81, JDouble) self.assertIsInstance(u, jpype.java.lang.Double) self.compareTest(u, 81) def testCharBox(self): u = passThrough(JChar('Q')) self.assertIsInstance(u, jpype.java.lang.Character) self.assertEqual(u, jpype.java.lang.Character('Q')) def testBooleanBox(self): u = passThrough(JBoolean(True)) self.assertIsInstance(u, jpype.java.lang.Boolean) self.assertEqual(u, jpype.java.lang.Boolean(True)) self.assertEqual(u, True) u = passThrough(JBoolean(False)) self.assertIsInstance(u, jpype.java.lang.Boolean) self.assertEqual(u, jpype.java.lang.Boolean(False)) self.assertEqual(u, False) def testByteBox(self): u = passThrough(JByte(5)) self.assertIsInstance(u, java.lang.Byte) self.assertEqual(u, java.lang.Byte(5)) def testShortBox(self): u = passThrough(JShort(5)) self.assertIsInstance(u, java.lang.Short) self.assertEqual(u, java.lang.Short(5)) def testIntBox(self): u = passThrough(JInt(5)) self.assertIsInstance(u, java.lang.Integer) self.assertEqual(u, java.lang.Integer(5)) def testLongBox(self): u = passThrough(JLong(5)) self.assertIsInstance(u, java.lang.Long) self.assertEqual(u, java.lang.Long(5)) def testFloatBox(self): u = passThrough(JFloat(5)) self.assertIsInstance(u, java.lang.Float) self.assertEqual(u, java.lang.Float(5)) def testDoubleBox(self): u = passThrough(JDouble(5)) self.assertIsInstance(u, java.lang.Double) self.assertEqual(u, java.lang.Double(5)) def testBooleanNull(self): n = JObject(None, JBoolean) self.assertIsInstance(n, java.lang.Boolean) self.assertEqual(n, None) self.assertNotEqual(n, True) self.assertNotEqual(n, False) with self.assertRaises(TypeError): int(n) with self.assertRaises(TypeError): float(n) self.assertEqual(str(n), str(None)) self.assertEqual(repr(n), str(None)) self.assertEqual(hash(n), hash(None)) u = passThrough(n) self.assertEqual(u, None) def testCharNull(self): n = JObject(None, JChar) self.assertIsInstance(n, java.lang.Character) self.assertNotEqual(n, 0) with self.assertRaises(TypeError): int(n) with self.assertRaises(TypeError): float(n) self.assertEqual(str(n), str(None)) self.assertEqual(repr(n), str(None)) self.assertEqual(hash(n), hash(None)) u = passThrough(n) self.assertEqual(u, None) def testByteNull(self): n = JObject(None, JByte) self.assertIsInstance(n, java.lang.Byte) self.assertNotEqual(n, 0) with self.assertRaises(TypeError): int(n) with self.assertRaises(TypeError): float(n) self.assertEqual(str(n), str(None)) self.assertEqual(repr(n), str(None)) self.assertEqual(hash(n), hash(None)) u = passThrough(n) self.assertEqual(u, None) def testShortNull(self): n = JObject(None, JShort) self.assertIsInstance(n, java.lang.Short) self.assertNotEqual(n, 0) with self.assertRaises(TypeError): int(n) with self.assertRaises(TypeError): float(n) self.assertEqual(str(n), str(None)) self.assertEqual(repr(n), str(None)) self.assertEqual(hash(n), hash(None)) u = passThrough(n) self.assertEqual(u, None) def testIntNull(self): n = JObject(None, JInt) self.assertIsInstance(n, java.lang.Integer) self.assertNotEqual(n, 0) with self.assertRaises(TypeError): int(n) with self.assertRaises(TypeError): float(n) self.assertEqual(str(n), str(None)) self.assertEqual(repr(n), str(None)) self.assertEqual(hash(n), hash(None)) u = passThrough(n) self.assertEqual(u, None) def testLongNull(self): n = JObject(None, JLong) self.assertIsInstance(n, java.lang.Long) self.assertNotEqual(n, 0) with self.assertRaises(TypeError): int(n) with self.assertRaises(TypeError): float(n) self.assertEqual(str(n), str(None)) self.assertEqual(repr(n), str(None)) self.assertEqual(hash(n), hash(None)) u = passThrough(n) self.assertEqual(u, None) def testFloatNull(self): n = JObject(None, JFloat) self.assertIsInstance(n, java.lang.Float) self.assertNotEqual(n, 0) self.assertNotEqual(n, 0.0) with self.assertRaises(TypeError): int(n) with self.assertRaises(TypeError): float(n) self.assertEqual(str(n), str(None)) self.assertEqual(repr(n), str(None)) self.assertEqual(hash(n), hash(None)) u = passThrough(n) self.assertEqual(u, None) def testDoubleNull(self): n = JObject(None, JDouble) self.assertIsInstance(n, java.lang.Double) self.assertNotEqual(n, 0) self.assertNotEqual(n, 0.0) with self.assertRaises(TypeError): int(n) with self.assertRaises(TypeError): float(n) self.assertEqual(str(n), str(None)) self.assertEqual(repr(n), str(None)) self.assertEqual(hash(n), hash(None)) u = passThrough(n) self.assertEqual(u, None) def testAsNumber(self): self.assertIsInstance(java.lang.Byte(1), java.lang.Number) self.assertIsInstance(java.lang.Short(1), java.lang.Number) self.assertIsInstance(java.lang.Integer(1), java.lang.Number) self.assertIsInstance(java.lang.Long(1), java.lang.Number) self.assertIsInstance(java.lang.Float(1), java.lang.Number) self.assertIsInstance(java.lang.Double(1), java.lang.Number) jpype-1.3.0/test/jpypetest/test_buffer.py000066400000000000000000000261001405671516700205450ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import jpype import sys import logging import time import common from jpype.types import * try: import numpy as np gotNP = True except ImportError: gotNP = False def haveNumpy(): return gotNP class BufferTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) def testToMemoryview(self): data = [1, 2, 3, 4, 5] ja = JArray(JInt)(data) m1 = memoryview(ja) def testDoubleOpen(self): data = [1, 2, 3, 4, 5] ja = JArray(JInt)(data) m1 = memoryview(ja) m2 = memoryview(ja) del m1 del m2 def testBytesToBytes(self): data = [0, 1, 2, 3, 4, 5] ja = JArray(JByte)(data) self.assertEqual(len(bytes(ja)), 6) def testShortToBytes(self): data = [0, 1, 2, 3, 4, 5] ja = JArray(JShort)(data) self.assertEqual(len(bytes(ja)), 6 * 2) def testIntToBytes(self): data = [0, 1, 2, 3, 4, 5] ja = JArray(JInt)(data) self.assertEqual(len(bytes(ja)), 6 * 4) def testLongToBytes(self): data = [0, 1, 2, 3, 4, 5] ja = JArray(JLong)(data) self.assertEqual(len(bytes(ja)), 6 * 8) def testMemoryViewWrite(self): data = [1, 2, 3, 4, 5] ja = JArray(JInt)(data) b = memoryview(ja) # Create a view with self.assertRaises(TypeError): b[0] = 123 # Alter the memory using the view @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testSlice(self): data = [0, 1, 2, 3, 4, 5] ja = JArray(JInt)(data) self.assertTrue(bytes(ja[1:3]) == bytes( np.array(data[1:3], dtype=np.int32))) self.assertTrue(bytes(ja[1:]) == bytes( np.array(data[1:], dtype=np.int32))) self.assertTrue(bytes(ja[:-1]) == bytes(np.array(data[:-1], dtype=np.int32))) self.assertTrue(bytes(ja[::2]) == bytes( np.array(data[::2], dtype=np.int32))) self.assertTrue(bytes(ja[::-1]) == bytes(np.array(data[::-1], dtype=np.int32))) self.assertTrue(bytes(ja[::-2]) == bytes(np.array(data[::-2], dtype=np.int32))) def executeConvert(self, jtype, dtype): n = 100 na = np.random.randint(0, 1, size=n).astype(np.bool) self.assertTrue(np.all(np.array(jtype(na), dtype=dtype) == np.array(na, dtype=dtype))) na = np.random.randint(-2**7, 2**7 - 1, size=n, dtype=np.int8) self.assertTrue(np.all(np.array(jtype(na), dtype=dtype) == np.array(na, dtype=dtype))) na = np.random.randint(0, 2**8 - 1, size=n, dtype=np.uint8) self.assertTrue(np.all(np.array(jtype(na), dtype=dtype) == np.array(na, dtype=dtype))) na = np.random.randint(-2**15, 2**15 - 1, size=n, dtype=np.int16) self.assertTrue(np.all(np.array(jtype(na), dtype=dtype) == np.array(na, dtype=dtype))) na = np.random.randint(0, 2**16 - 1, size=n, dtype=np.uint16) self.assertTrue(np.all(np.array(jtype(na), dtype=dtype) == np.array(na, dtype=dtype))) na = np.random.randint(-2**31, 2**31 - 1, size=n, dtype=np.int32) self.assertTrue(np.all(np.array(jtype(na), dtype=dtype) == np.array(na, dtype=dtype))) na = np.random.randint(0, 2**32 - 1, size=n, dtype=np.uint32) self.assertTrue(np.all(np.array(jtype(na), dtype=dtype) == np.array(na, dtype=dtype))) na = np.random.randint(-2**63, 2**63 - 1, size=n, dtype=np.int64) self.assertTrue(np.all(np.array(jtype(na), dtype=dtype) == np.array(na, dtype=dtype))) na = np.random.randint(0, 2**64 - 1, size=n, dtype=np.uint64) self.assertTrue(np.all(np.array(jtype(na), dtype=dtype) == np.array(na, dtype=dtype))) na = np.random.random(n).astype(np.float32) self.assertTrue(np.all(np.array(jtype(na), dtype=dtype) == np.array(na, dtype=dtype))) na = np.random.random(n).astype(np.float64) self.assertTrue(np.all(np.array(jtype(na), dtype=dtype) == np.array(na, dtype=dtype))) @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testBoolConvert(self): self.executeConvert(JArray(JBoolean), np.bool) @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testByteConvert(self): self.executeConvert(JArray(JByte), np.int8) @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testShortConvert(self): self.executeConvert(JArray(JShort), np.int16) @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testIntConvert(self): self.executeConvert(JArray(JInt), np.int32) @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testLongConvert(self): self.executeConvert(JArray(JLong), np.int64) @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testFloatConvert(self): self.executeConvert(JArray(JFloat), np.float32) @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testDoubleConvert(self): self.executeConvert(JArray(JDouble), np.float64) def executeIntTest(self, jtype, limits, size, dtype, code): data = np.random.randint(limits[0], limits[1], size=size, dtype=dtype) a = JArray(jtype, data.ndim)(data.tolist()) u = np.array(a) self.assertTrue(np.all(data == u)) mv = memoryview(a) self.assertEqual(mv.format, code) self.assertEqual(mv.shape, data.shape) self.assertTrue(mv.readonly) def executeFloatTest(self, jtype, size, dtype, code): data = np.random.rand(*size).astype(dtype) a = JArray(jtype, data.ndim)(data) u = np.array(a) self.assertTrue(np.all(data == u)) mv = memoryview(a) self.assertEqual(mv.format, code) self.assertEqual(mv.shape, data.shape) self.assertTrue(mv.readonly) @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testBooleanToNP1D(self): self.executeIntTest(JBoolean, [0, 1], (100,), np.bool, "?") @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testCharToNP1D(self): self.executeIntTest(JChar, [0, 2**16], (100,), np.uint16, "H") @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testByteToNP1D(self): self.executeIntTest(JByte, [-2**7, 2**7 - 1], (100,), np.int8, "b") @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testShortToNP1D(self): self.executeIntTest(JShort, [-2**15, 2**15 - 1], (100,), np.int16, "h") @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testIntToNP1D(self): self.executeIntTest(JInt, [-2**31, 2**31 - 1], (100,), np.int32, "i") @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testLongToNP1D(self): self.executeIntTest(JLong, [-2**63, 2**63 - 1], (100,), np.int64, "q") @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testFloatToNP1D(self): self.executeFloatTest(JFloat, (100,), np.float32, "f") @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testDoubleToNP1D(self): self.executeFloatTest(JDouble, (100,), np.float64, "d") @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testBooleanToNP2D(self): self.executeIntTest(JBoolean, [0, 1], (11, 10), np.bool, "?") @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testCharToNP2D(self): self.executeIntTest(JChar, [0, 2**16], (11, 10), np.uint16, "H") @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testByteToNP2D(self): self.executeIntTest(JByte, [-2**7, 2**7 - 1], (11, 10), np.int8, "b") @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testShortToNP2D(self): self.executeIntTest(JShort, [-2**15, 2**15 - 1], (11, 10), np.int16, "h") @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testIntToNP2D(self): self.executeIntTest(JInt, [-2**31, 2**31 - 1], (11, 10), np.int32, "i") @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testLongToNP2D(self): self.executeIntTest(JLong, [-2**63, 2**63 - 1], (11, 10), np.int64, "q") @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testFloatToNP2D(self): self.executeFloatTest(JFloat, (11, 10), np.float32, "f") @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testDoubleToNP2D(self): self.executeFloatTest(JDouble, (11, 10), np.float64, "d") @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testBooleanToNP3D(self): self.executeIntTest(JBoolean, [0, 1], (11, 10, 9), np.bool, "?") @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testCharToNP3D(self): self.executeIntTest(JChar, [0, 2**16], (11, 10, 9), np.uint16, "H") @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testByteToNP3D(self): self.executeIntTest(JByte, [-2**7, 2**7 - 1], (11, 10, 9), np.int8, "b") @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testShortToNP3D(self): self.executeIntTest(JShort, [-2**15, 2**15 - 1], (11, 10, 9), np.int16, "h") @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testIntToNP3D(self): self.executeIntTest(JInt, [-2**31, 2**31 - 1], (11, 10, 9), np.int32, "i") @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testLongToNP3D(self): self.executeIntTest(JLong, [-2**63, 2**63 - 1], (11, 10, 9), np.int64, "q") @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testFloatToNP3D(self): self.executeFloatTest(JFloat, (11, 10, 9), np.float32, "f") @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testDoubleToNP3D(self): self.executeFloatTest(JDouble, (11, 10, 9), np.float64, "d") jpype-1.3.0/test/jpypetest/test_bytebuffer.py000066400000000000000000000032661405671516700214410ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import jpype import _jpype import common class ByteBufferCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) def testConvertToDirectBuffer(self): a = bytearray([0, 0, 0, 0]) bb = jpype.nio.convertToDirectBuffer(a) self.assertIsInstance(bb, jpype.JClass("java.nio.DirectByteBuffer")) bb.put(1) bb.put(2) bb.put(3) bb.put(4) self.assertEqual(a, bytearray([1, 2, 3, 4])) with self.assertRaises(jpype.JException): bb.put(5) def testConvertToDirectBufferFail(self): a = bytes([0, 0, 0, 0]) with self.assertRaises(ValueError): bb = jpype.nio.convertToDirectBuffer(a) def testRepr(self): a = bytearray([0, 0, 0, 0]) bb = jpype.nio.convertToDirectBuffer(a) self.assertIsInstance(repr(bb), str) self.assertEqual(repr(bb), "") jpype-1.3.0/test/jpypetest/test_caller_sensitive.py000066400000000000000000000100311405671516700226230ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import jpype import common class JCallerSensitiveCase(common.JPypeTestCase): """ Test for caller sensitive methods. Java uses a special pattern to deal with the security manager. It uses the stack to find the callers class and then decides if the call is permitted. But when we call from JNI there is no class. Thus, we need a special caller pattern which proxies to Java and then calls the method. This alternative method has to be tested against all of the different patterns (static, member), returning (void, primitive, object), called with (nothing, object, primitive, many, varargs) Unfortunately, the actual problematic method in Java is private, so we can't get to it directly. Thus will will perform indirect tests. For now we do not support caller sensitive constructors. """ def setUp(self): common.JPypeTestCase.setUp(self) if not jpype.getJVMVersion() > (1, 8, 0): raise common.unittest.SkipTest self.Class = jpype.JClass("jpype.method.Caller") self.obj = self.Class() def testCallStatic(self): self.assertIsInstance(self.Class.callObjectStatic(), self.Class) def testCallStaticAsMember(self): self.assertIsInstance(self.obj.callObjectStatic(), self.Class) def testCallMember(self): self.assertIsInstance(self.obj.callObjectMember(), self.Class) def testCallMemberFromClass(self): self.assertIsInstance( self.Class.callObjectMember(self.obj), self.Class) def testCallVoidStatic(self): self.assertEqual(self.Class.callVoidStatic(), None) def testCallVoidStaticAsMember(self): self.assertEqual(self.obj.callVoidStatic(), None) def testCallVoidMemberFromClass(self): self.assertEqual(self.Class.callVoidMember(self.obj), None) def testCallIntegerStatic(self): self.assertEqual(self.Class.callIntegerStatic(), 123) def testCallIntegerMember(self): self.assertEqual(self.obj.callIntegerMember(), 123) def testCallIntegerStaticAsMember(self): self.assertEqual(self.obj.callIntegerStatic(), 123) def testCallIntegerMemberFromClass(self): self.assertEqual(self.Class.callIntegerMember(self.obj), 123) def testArgs(self): self.assertEqual(self.obj.callArgs(1, 2), 2) def testArgsFromClass(self): self.assertEqual(self.Class.callArgs(self.obj, 1, 2), 2) def testPrimitive(self): self.assertEqual(self.obj.callArg1(123), 123) def testPrimitiveFromClass(self): self.assertEqual(self.Class.callArg1(self.obj, 125), 125) def testVarArgs(self): self.assertEqual(tuple(self.obj.callVarArgs(1, 2, 3)), (2, 3)) def testVarArgsFromClass(self): self.assertEqual( tuple(self.Class.callVarArgs(self.obj, 1, 2, 3)), (2, 3)) def testDeclaredMethod(self): self.assertIsInstance(jpype.java.lang.Object.class_.getDeclaredMethod( 'wait'), jpype.java.lang.reflect.Method) def testStackWalker1(self): with self.assertRaises(jpype.java.lang.IllegalCallerException): self.obj.callStackWalker1() def testStackWalker2(self): self.assertEqual(self.obj.callStackWalker2(), jpype.JClass( jpype.java.lang.Class.forName("org.jpype.JPypeContext")).class_) jpype-1.3.0/test/jpypetest/test_charSequence.py000066400000000000000000000025221405671516700217040ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import jpype import sys import logging import time import common class ConversionCharSequenceTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) def testAutoConvert(self): Instant = jpype.JClass("java.time.Instant") now = "2019-11-12T03:20:54.710948400Z" then = Instant.parse(now) self.assertEqual(str(then), now) then = Instant.parse(jpype.JString(now)) self.assertEqual(str(then), now) then = Instant.parse(jpype.JObject(now, "java.lang.CharSequence")) self.assertEqual(str(then), now) jpype-1.3.0/test/jpypetest/test_classhints.py000066400000000000000000000055231405671516700214550ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import jpype import common class MyImpl(object): def blah(self): pass class ClassHintsTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) self.Custom = jpype.JClass("jpype.classhints.Custom") self.ClassHintsTest = jpype.JClass("jpype.classhints.ClassHintsTest") @jpype.JImplements("jpype.classhints.Custom") class MyCustom(object): def __init__(self, arg): self.arg = arg self.MyCustom = MyCustom def testCharSequence(self): Instant = jpype.JClass("java.time.Instant") s = "2019-12-21T05:26:13.223189Z" self.assertTrue(str(Instant.parse(s)), s) def testInstant(self): import datetime now = datetime.datetime.utcnow() Instant = jpype.JClass("java.time.Instant") self.assertIsInstance(jpype.JObject(now, Instant), Instant) def testPath(self): import pathlib JPath = jpype.JClass("java.nio.file.Path") self.assertIsInstance(jpype.JObject( pathlib.Path(__file__).absolute(), JPath), JPath) def testFile(self): import pathlib JFile = jpype.JClass("java.io.File") self.assertIsInstance(jpype.JObject( pathlib.Path(__file__).absolute(), JFile), JFile) def testConvertExact(self): cht = self.ClassHintsTest with self.assertRaises(TypeError): cht.call("hello") @jpype.JConversion(self.Custom, exact=str) def StrToCustom(jcls, args): return self.MyCustom(args) cht.call("hello") self.assertIsInstance(cht.input, self.MyCustom) self.assertEqual(cht.input.arg, "hello") def testConvertAttribute(self): cht = self.ClassHintsTest with self.assertRaises(TypeError): cht.call(MyImpl()) @jpype.JConversion(self.Custom, attribute="blah") def StrToCustom(jcls, args): return self.MyCustom(args) cht.call(MyImpl()) self.assertIsInstance(cht.input, self.MyCustom) self.assertIsInstance(cht.input.arg, MyImpl) jpype-1.3.0/test/jpypetest/test_closeable.py000066400000000000000000000124221405671516700212270ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import jpype import common import sys def pythonNewerThan(major, minor): return sys.version_info[0] > major or (sys.version_info[0] == major and sys.version_info[1] > minor) class CloseableTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) def testCloseable(self): CloseableTest = jpype.JClass("jpype.closeable.CloseableTest") CloseableTest.reset() self.assertFalse(CloseableTest.closed) with CloseableTest() as myFile: myFile.print_("hello 1") self.assertEqual(CloseableTest.printed, "hello 1") self.assertTrue(CloseableTest.closed) @common.unittest.skipUnless(pythonNewerThan(3, 0), "requires python 3") def testCloseableFail(self): CloseableTest = jpype.JClass("jpype.closeable.CloseableTest") CloseableTest.reset() CloseableTest.willfail = True self.assertFalse(CloseableTest.closed) ex1 = None try: with CloseableTest() as myFile: myFile.print_("hello 1") try: raise Exception('foo') except Exception as ex: pass except Exception as ex: ex1 = ex self.assertTrue(ex1) self.assertEqual(CloseableTest.printed, "hello 1") self.assertTrue(CloseableTest.closed) def testCloseablePyExcept(self): CloseableTest = jpype.JClass("jpype.closeable.CloseableTest") CloseableTest.reset() self.assertFalse(CloseableTest.closed) try: with CloseableTest() as myFile: myFile.print_("hello 2") raise TypeError("Python exception") myFile.print_("there") except Exception as ex: self.assertIsInstance(ex, TypeError) self.assertEqual(CloseableTest.printed, "hello 2") self.assertTrue(CloseableTest.closed) @common.unittest.skipUnless(pythonNewerThan(2, 6), "Earlier python does not support stacked exceptions.") def testCloseablePyExceptFail(self): CloseableTest = jpype.JClass("jpype.closeable.CloseableTest") CloseableTest.reset() CloseableTest.willfail = True self.assertFalse(CloseableTest.closed) try: with CloseableTest() as myFile: myFile.print_("hello 3") raise TypeError("Python exception") myFile.print_("there") except TypeError as ex: self.assertIsInstance(ex, TypeError) self.assertEqual(CloseableTest.printed, "hello 3") self.assertTrue(CloseableTest.closed) self.assertTrue(CloseableTest.failed) def testCloseableJExcept(self): CloseableTest = jpype.JClass("jpype.closeable.CloseableTest") CloseableTest.reset() self.assertFalse(CloseableTest.closed) try: with CloseableTest() as myFile: myFile.print_("hello 4") myFile.throwException() myFile.print_("there") except Exception as ex: self.assertIsInstance(ex, jpype.JException, 'type is %s' % type(ex)) self.assertEqual(ex.getMessage(), 'oh no!') self.assertEqual(CloseableTest.printed, "hello 4") self.assertTrue(CloseableTest.closed) @common.unittest.skipUnless(pythonNewerThan(2, 6), "Earlier python does not support stacked exceptions.") def testCloseableJExceptFail(self): CloseableTest = jpype.JClass("jpype.closeable.CloseableTest") CloseableTest.reset() CloseableTest.willfail = True self.assertFalse(CloseableTest.closed) try: with CloseableTest() as myFile: myFile.print_("hello 5") myFile.throwException() myFile.print_("there") except Exception as ex: self.assertIsInstance(ex, jpype.JException, 'type is %s' % type(ex)) self.assertEqual(ex.getMessage(), 'oh no!') # fail if get "oh my?" self.assertEqual(CloseableTest.printed, "hello 5") self.assertTrue(CloseableTest.closed) self.assertTrue(CloseableTest.failed) def testCloseableAttr(self): cls = jpype.JClass("java.io.Closeable") self.assertTrue(hasattr(cls, '__enter__')) self.assertTrue(hasattr(cls, '__exit__')) def testAutoCloseableAttr(self): cls = jpype.JClass("java.lang.AutoCloseable") self.assertTrue(hasattr(cls, '__enter__')) self.assertTrue(hasattr(cls, '__exit__')) jpype-1.3.0/test/jpypetest/test_closed.py000066400000000000000000000033231405671516700205470ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import jpype import common class ClosedTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) def testObjects(self): from jpype import java s = java.lang.String('foo') s._allowed = 1 try: s.forbidden = 1 except AttributeError: pass else: raise AssertionError("AttributeError not raised") def testArrays(self): s = jpype.JArray(jpype.JInt)(5) # Setting private members is allowed s._allowed = 1 try: # Setting public members is prohibited s.forbidden = 1 except AttributeError: pass else: raise AssertionError("AttributeError not raised") def testStatic(self): static = jpype.JClass('jpype.objectwrapper.StaticTest') self.assertEqual(static.i, 1) self.assertEqual(static.d, 1.2345) self.assertEqual(static.s, "hello") jpype-1.3.0/test/jpypetest/test_collection.py000066400000000000000000000222121405671516700214270ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import jpype from jpype.types import * import common import collections.abc class CollectionCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) @common.requirePythonAfter((3, 6, 0)) def testCollectionABC(self): JCollection = JClass('java.util.Collection') self.assertFalse(issubclass(JCollection, collections.abc.Sequence)) self.assertFalse(issubclass(JCollection, collections.abc.Reversible)) self.assertTrue(issubclass(JCollection, collections.abc.Collection)) self.assertTrue(issubclass(JCollection, collections.abc.Iterable)) self.assertTrue(issubclass(JCollection, collections.abc.Sized)) def testCollectionDelItem(self): ja = JClass('java.util.ArrayList')(['1', '2', '3']) jc = JObject(ja, 'java.util.Collection') with self.assertRaisesRegex(TypeError, 'remove'): del jc[1] def testListAddAll(self): l = [1, 2, 3, 4] l2 = ['a', 'b'] jlist = JClass("java.util.ArrayList")() jlist.addAll(l) jcollection = JObject(jlist, JClass("java.util.Collection")) jcollection.addAll(l2) l.extend(l2) self.assertEqual(l, list(jcollection)) class CollectionIteratorCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) def testIterator(self): al = JClass("java.util.ArrayList")() itr = al.iterator() self.assertEqual(itr, iter(itr)) class CollectionListCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) def testListAdd(self): collection = JClass("java.util.ArrayList")() collection.add(1) collection.add(2) self.assertEqual([1, 2], [i for i in collection]) def testListGet(self): jlist = JClass("java.util.ArrayList")() jlist.addAll([1, 2, 3, 4]) self.assertEqual(jlist[0], 1) self.assertEqual(jlist[3], 4) self.assertEqual(jlist[-1], 4) self.assertEqual(jlist[-4], 1) def testListSlice(self): jlist = JClass("java.util.ArrayList")() jlist.addAll([1, 2, 3, 4]) jlist[1:3] = [5, 6] self.assertEqual(jlist[1], 5) self.assertEqual(jlist[2], 6) def testListDel(self): jlist = JClass("java.util.ArrayList")() jlist.addAll([1, 2, 3, 4]) del jlist[0] self.assertEqual(len(jlist), 3) self.assertEqual(jlist[0], 2) def testListSetItemNeg(self): l = [1, 2, 3, 4] jlist = JClass("java.util.ArrayList")() jlist.addAll([1, 2, 3, 4]) jlist[-1] = 5 l[-1] = 5 self.assertEqual(l, list(jlist)) jlist[-2] = 6 l[-2] = 6 self.assertEqual(l, list(jlist)) with self.assertRaises(IndexError): jlist[-5] = 6 def testListIter(self): ls = JClass('java.util.ArrayList')([0, 1, 2, 3]) for i, j in enumerate(ls): self.assertEqual(i, j) def testUnmodifiableNext(self): ArrayList = JClass('java.util.ArrayList') Collections = JClass('java.util.Collections') a = ArrayList() a.add("first") a.add("second") a.add("third") for i in a: pass for i in Collections.unmodifiableList(a): pass @common.requirePythonAfter((3, 6, 0)) def testListABC(self): l = ['a', 'b', 'c', 'b'] JList = JClass('java.util.ArrayList') al = JList(l) for i, j in zip(reversed(al), reversed(l)): self.assertEqual(i, j) self.assertEqual(object() in al, object() in l) self.assertEqual('a' in al, 'a' in l) self.assertEqual(al.index('b'), l.index('b')) self.assertEqual(al.count('b'), l.count('b')) with self.assertRaises(ValueError): al.index(object()) self.assertEqual(al.count(object()), l.count(object())) self.assertIsInstance(al, collections.abc.Sequence) self.assertIsInstance(al, collections.abc.Reversible) self.assertIsInstance(al, collections.abc.Collection) self.assertIsInstance(al, collections.abc.Iterable) self.assertIsInstance(al, collections.abc.Sized) class CollectionMapCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) def testIterateMap(self): collection = JClass('java.util.HashMap')() collection.put('A', 1) collection.put('B', 2) asdict = dict() for x in collection.entrySet(): asdict[str(x.getKey())] = x.getValue().longValue() self.assertEqual(asdict, {'A': 1, 'B': 2}) def testMapPut(self): jmap = JClass("java.util.HashMap")() jmap["a"] = 1 self.assertEqual(jmap["a"], 1) def testMapPutAll(self): jmap = JClass("java.util.HashMap")() dic = {"a": "1", "b": "2", "c": "3"} jmap.putAll(dic) self.assertEqual(jmap["a"], "1") self.assertEqual(jmap["b"], "2") self.assertEqual(jmap["c"], "3") with self.assertRaises(TypeError): jmap.putAll([1, 2, 3]) def testMapKeyError(self): hm = JClass('java.util.HashMap')() with self.assertRaises(KeyError): hm['foo'] hm['foo'] = None self.assertEqual(hm['foo'], None) def testHashMapEntryIter(self): hm = JClass('java.util.HashMap')() hm['alice'] = 'alice' hm['betty'] = 'betty' hm['catty'] = 'catty' for p, v in hm.entrySet(): self.assertEqual(p, v) def testTreeMapEntryIter(self): hm = JClass('java.util.TreeMap')() hm['alice'] = 'alice' hm['betty'] = 'betty' hm['catty'] = 'catty' for p, v in hm.entrySet(): self.assertEqual(p, v) def testMapEntry(self): hm = JClass('java.util.TreeMap')() hm['alice'] = 'alice' h = hm.entrySet() self.assertEqual(len(h.iterator().next()), 2) def testEnumMap(self): enumclass = JClass('jpype.collection.TestEnum') enummap = JClass('java.util.EnumMap')(enumclass) enummap.put(enumclass.A, 'ABC') enummap.put(enumclass.B, 'DEF') asdict = dict() for x in enummap.entrySet(): asdict[str(x.getKey())] = x.getValue() self.assertEqual({'A': 'ABC', 'B': 'DEF'}, asdict) def testSetDelItem(self): hs = JClass('java.util.HashSet')() hs.add('a') hs.add('b') hs.add('c') self.assertIn('a', hs) del hs['a'] self.assertNotIn('a', hs) def testHashMapCtor(self): HashMap = JClass('java.util.HashMap') dc = dict() dc['fred'] = 1 dc['george'] = 2 dc['paul'] = 3 hm = HashMap(dc) for p, v in dc.items(): self.assertEqual(hm[p], v) def testHashMapPutAll(self): HashMap = JClass('java.util.HashMap') hm = HashMap() dc = dict() dc['fred'] = 1 dc['george'] = 2 dc['paul'] = 3 hm.putAll(dc) for p, v in dc.items(): self.assertEqual(hm[p], v) def testHashMapConvert(self): HashMap = JClass('java.util.HashMap') hm = HashMap() hm['fred'] = 1 hm['george'] = 2 hm['paul'] = 3 dc = dict(hm) for p, v in hm.items(): self.assertEqual(dc[p], v) def testMapABC(self): from collections.abc import Mapping, Sized, Iterable, Container hm = JClass('java.util.HashMap')() self.assertIsInstance(hm, Sized) self.assertIsInstance(hm, Iterable) self.assertIsInstance(hm, Container) self.assertIsInstance(hm, Mapping) def testMapContains(self): hm = JClass('java.util.HashMap')() hm['fred'] = 1 hm['george'] = 2 hm['paul'] = 3 self.assertTrue("fred" in hm) self.assertFalse("sally" in hm) def testMapNoConversion(self): hm = JClass("java.util.HashMap")() self.assertFalse(object() in hm) with self.assertRaises(KeyError): hm[object()] class CollectionEnumerationCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) def testEnumeration(self): st = JClass('java.util.StringTokenizer')("this is a test") out = [] for i in st: out.append(str(i)) self.assertEqual(len(i), 4) self.assertEqual(" ".join(out), "this is a test") jpype-1.3.0/test/jpypetest/test_comparable.py000066400000000000000000000053531405671516700214100ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import sys import jpype import common class ComparableTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) def testComparable(self): a = jpype.java.time.Instant.ofEpochSecond(10000000) b = jpype.java.time.Instant.ofEpochSecond(10000001) self.assertFalse(a < a) self.assertFalse(a > a) self.assertTrue(a >= a) self.assertTrue(a <= a) self.assertTrue(a == a) self.assertFalse(a != a) self.assertTrue(a < b) self.assertFalse(a > b) self.assertFalse(a >= b) self.assertTrue(a <= b) self.assertFalse(a == b) self.assertTrue(a != b) def testComparableHash(self): i = jpype.java.math.BigInteger("1000000000000") self.assertIsInstance(hash(i), int) def testComparableNull(self): Instant = jpype.JClass("java.time.Instant") i1 = Instant.parse("1970-01-01T00:00:00Z") i3 = jpype.JObject(None, Instant) self.assertTrue(i1 == i1) self.assertFalse(i1 == i3) self.assertFalse(i3 == i1) self.assertTrue(i1 != i3) self.assertTrue(i3 != i1) with self.assertRaises(ValueError): print(i1 < i3) with self.assertRaises(ValueError): print(i1 <= i3) with self.assertRaises(ValueError): print(i1 > i3) with self.assertRaises(ValueError): print(i1 >= i3) with self.assertRaises(ValueError): print(i3 < i1) with self.assertRaises(ValueError): print(i3 <= i1) with self.assertRaises(ValueError): print(i3 > i1) with self.assertRaises(ValueError): print(i3 >= i1) with self.assertRaises(ValueError): print(i3 < i3) with self.assertRaises(ValueError): print(i3 <= i3) with self.assertRaises(ValueError): print(i3 > i3) with self.assertRaises(ValueError): print(i3 >= i3) jpype-1.3.0/test/jpypetest/test_conversion.py000066400000000000000000000131301405671516700214600ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import common import jpype import _jpype from jpype.types import * class ConversionTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) self.jc1 = jpype.JClass("java.lang.String") self.jc2 = jpype.JClass("java.lang.Integer") def testList(self): cls = JClass('jpype.collection.CollectionTest') self.assertIsInstance(cls.testList( [1, 2, 3]), JClass('java.util.List')) def testMap(self): cls = JClass('jpype.collection.CollectionTest') self.assertIsInstance(cls.testMap( {'a': 1, 'b': 2}), JClass('java.util.Map')) def testCanConvertExact(self): self.assertEqual(self.jc1._canConvertToJava("a"), "exact") def testCanConvertNone(self): self.assertEqual(self.jc1._canConvertToJava(1), "none") def testCanConvertExplicit(self): self.assertEqual( self.jc2._canConvertToJava(1), "explicit") def testCanConvertImplicit(self): self.assertEqual( self.jc1._canConvertToJava(None), "implicit") def testConvertExact(self): self.assertIsInstance( self.jc1._convertToJava("a"), self.jc1) def testConvertImplicit(self): self.assertIsInstance( self.jc1._convertToJava(None), self.jc1) def testConvertExplicit(self): self.assertIsInstance( self.jc2._convertToJava(1), self.jc2) def testConvertNone(self): with self.assertRaises(TypeError): self.jc1._convertToJava(1) def testUnbox(self): jf = JClass('jpype.common.Fixture') java = jpype.java jf.static_bool_field = java.lang.Boolean(True) self.assertEqual(jf.static_bool_field, True) jf.static_char_field = java.lang.Character("a") self.assertEqual(jf.static_char_field, "a") jf.static_byte_field = java.lang.Byte(123) self.assertEqual(jf.static_byte_field, 123) jf.static_short_field = java.lang.Short(123) self.assertEqual(jf.static_short_field, 123) jf.static_int_field = java.lang.Integer(123) self.assertEqual(jf.static_int_field, 123) jf.static_long_field = java.lang.Long(123) self.assertEqual(jf.static_long_field, 123) jf.static_float_field = java.lang.Float(123) self.assertEqual(jf.static_float_field, 123) jf.static_double_field = java.lang.Double(123) self.assertEqual(jf.static_double_field, 123) def testUnboxFail(self): java = jpype.java with self.assertRaises(TypeError): JBoolean._convertToJava(java.lang.Double(1)) with self.assertRaises(TypeError): JChar._convertToJava(java.lang.Double(1)) with self.assertRaises(TypeError): JByte._convertToJava(java.lang.Boolean(1)) with self.assertRaises(TypeError): JShort._convertToJava(java.lang.Boolean(1)) with self.assertRaises(TypeError): JInt._convertToJava(java.lang.Boolean(1)) with self.assertRaises(TypeError): JLong._convertToJava(java.lang.Boolean(1)) with self.assertRaises(TypeError): JFloat._convertToJava(java.lang.Boolean(1)) with self.assertRaises(TypeError): JDouble._convertToJava(java.lang.Boolean(1)) def testBox(self): java = jpype.java self.assertEqual(java.lang.Boolean(JBoolean(True)), True) # FIXME this one fails #self.assertEqual(java.lang.Character(JChar("A")), "A") self.assertEqual(java.lang.Byte(JByte(123)), 123) self.assertEqual(java.lang.Short(JShort(123)), 123) self.assertEqual(java.lang.Integer(JInt(123)), 123) self.assertEqual(java.lang.Long(JLong(123)), 123) self.assertEqual(java.lang.Float(JFloat(123)), 123) self.assertEqual(java.lang.Double(JDouble(123)), 123) def testCharConversion(self): self.assertEqual(JChar._canConvertToJava("a"), "implicit") self.assertEqual(JChar._canConvertToJava(bytes([1])), "implicit") self.assertEqual(JChar._canConvertToJava(bytes([1, 1])), "none") # This test is wrong 'char q = (char) 1000000;' works in Java # def testCharOverflow(self): # with self.assertRaises(OverflowError): # JChar(1000000) def testCharBytes(self): # setArrayRange directly calls Char conversion so it is a good way # to test without checking if conversion is possible first ja = JArray(JChar)(2) with self.assertRaises(ValueError): ja[0:1] = [bytes([1, 1, 1])] with self.assertRaises(OverflowError): ja[0:1] = [1000000] with self.assertRaises(ValueError): ja[0:1] = ["AAA"] with self.assertRaises(ValueError): ja[0:1] = ["\U0001F600"] with self.assertRaises(TypeError): ja[0:1] = [object()] ja[0:1] = ["\u265E"] jpype-1.3.0/test/jpypetest/test_conversionInt.py000066400000000000000000000067261405671516700221500ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import jpype from jpype.types import * import sys import logging import time import common def haveNumpy(): try: import numpy return True except ImportError: return False class ConversionIntTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) self.Test = jpype.JClass("jpype.common.Fixture")() def testIntFromInt(self): self.assertEqual(self.Test.callInt(int(123)), 123) @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testIntFromNPInt(self): import numpy as np self.assertEqual(self.Test.callInt(np.int(123)), 123) @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testIntFromNPInt8(self): import numpy as np self.assertEqual(self.Test.callInt(np.int8(123)), 123) self.assertEqual(self.Test.callInt(np.uint8(123)), 123) @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testIntFromNPInt16(self): import numpy as np self.assertEqual(self.Test.callInt(np.int16(123)), 123) self.assertEqual(self.Test.callInt(np.uint16(123)), 123) @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testIntFromNPInt32(self): import numpy as np self.assertEqual(self.Test.callInt(np.int32(123)), 123) self.assertEqual(self.Test.callInt(np.uint32(123)), 123) @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testIntFromNPInt64(self): import numpy as np self.assertEqual(self.Test.callInt(np.int64(123)), 123) self.assertEqual(self.Test.callInt(np.uint64(123)), 123) def testIntFromFloat(self): with self.assertRaises(TypeError): self.Test.callInt(float(2)) @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testIntFromNPFloat(self): import numpy as np with self.assertRaises(TypeError): self.Test.callInt(np.float(2)) @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testIntFromNPFloat32(self): import numpy as np with self.assertRaises(TypeError): self.Test.callInt(np.float32(2)) @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testIntFromNPFloat64(self): import numpy as np with self.assertRaises(TypeError): self.Test.callInt(np.float64(2)) def testIntRange(self): with self.assertRaises(OverflowError): self.Test.callInt(int(1e10)) with self.assertRaises(OverflowError): self.Test.callInt(int(-1e10)) def testIntFromNone(self): with self.assertRaises(TypeError): self.Test.callInt(None) jpype-1.3.0/test/jpypetest/test_conversionLong.py000066400000000000000000000067641405671516700223170ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import jpype from jpype.types import * import sys import logging import time import common def haveNumpy(): try: import numpy return True except ImportError: return False class ConversionLongTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) self.Test = jpype.JClass("jpype.common.Fixture")() def testLongFromInt(self): self.assertEqual(self.Test.callLong(int(123)), 123) @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testLongFromNPInt(self): import numpy as np self.assertEqual(self.Test.callLong(np.int(123)), 123) @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testLongFromNPInt8(self): import numpy as np self.assertEqual(self.Test.callLong(np.int8(123)), 123) self.assertEqual(self.Test.callLong(np.uint8(123)), 123) @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testLongFromNPInt16(self): import numpy as np self.assertEqual(self.Test.callLong(np.int16(123)), 123) self.assertEqual(self.Test.callLong(np.uint16(123)), 123) @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testLongFromNPInt32(self): import numpy as np self.assertEqual(self.Test.callLong(np.int32(123)), 123) self.assertEqual(self.Test.callLong(np.uint32(123)), 123) @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testLongFromNPInt64(self): import numpy as np self.assertEqual(self.Test.callLong(np.int64(123)), 123) self.assertEqual(self.Test.callLong(np.uint64(123)), 123) def testLongFromFloat(self): with self.assertRaises(TypeError): self.Test.callLong(float(2)) @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testLongFromNPFloat(self): import numpy as np with self.assertRaises(TypeError): self.Test.callLong(np.float(2)) @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testLongFromNPFloat32(self): import numpy as np with self.assertRaises(TypeError): self.Test.callLong(np.float32(2)) @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testLongFromNPFloat64(self): import numpy as np with self.assertRaises(TypeError): self.Test.callLong(np.float64(2)) def testLongRange(self): with self.assertRaises(OverflowError): self.Test.callLong(int(1e30)) with self.assertRaises(OverflowError): self.Test.callLong(int(-1e30)) def testLongFromNone(self): with self.assertRaises(TypeError): self.Test.callLong(None) jpype-1.3.0/test/jpypetest/test_conversionShort.py000066400000000000000000000070221405671516700225030ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import jpype from jpype.types import * import sys import logging import time import common def haveNumpy(): try: import numpy return True except ImportError: return False class ConversionShortTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) self.Test = jpype.JClass("jpype.common.Fixture")() def testShortFromInt(self): self.assertEqual(self.Test.callShort(int(123)), 123) @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testShortFromNPInt(self): import numpy as np self.assertEqual(self.Test.callShort(np.int(123)), 123) @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testShortFromNPInt8(self): import numpy as np self.assertEqual(self.Test.callShort(np.int8(123)), 123) self.assertEqual(self.Test.callShort(np.uint8(123)), 123) @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testShortFromNPInt16(self): import numpy as np self.assertEqual(self.Test.callShort(np.int16(123)), 123) self.assertEqual(self.Test.callShort(np.uint16(123)), 123) @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testShortFromNPInt32(self): import numpy as np self.assertEqual(self.Test.callShort(np.int32(123)), 123) self.assertEqual(self.Test.callShort(np.uint32(123)), 123) @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testShortFromNPInt64(self): import numpy as np self.assertEqual(self.Test.callShort(np.int64(123)), 123) self.assertEqual(self.Test.callShort(np.uint64(123)), 123) def testShortFromFloat(self): with self.assertRaises(TypeError): self.Test.callShort(float(2)) @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testShortFromNPFloat(self): import numpy as np with self.assertRaises(TypeError): self.Test.callShort(np.float(2)) @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testShortFromNPFloat32(self): import numpy as np with self.assertRaises(TypeError): self.Test.callShort(np.float32(2)) @common.unittest.skipUnless(haveNumpy(), "numpy not available") def testShortFromNPFloat64(self): import numpy as np with self.assertRaises(TypeError): self.Test.callShort(np.float64(2)) def testShortRange(self): with self.assertRaises(OverflowError): self.Test.callShort(int(1e10)) with self.assertRaises(OverflowError): self.Test.callShort(int(-1e10)) def testShortFromNone(self): with self.assertRaises(TypeError): self.Test.callShort(None) jpype-1.3.0/test/jpypetest/test_core.py000066400000000000000000000042371405671516700202330ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** from unittest import mock import jpype import common from jpype.types import * class JCharTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) @mock.patch('jpype._core.sys') def testVersion(self, mock_sys): mock_sys.version_info = (2, 7) with self.assertRaises(ImportError): jpype._core.versionTest() mock_sys.version_info = (3, 8) jpype._core.versionTest() def testShutdownHook(self): Thread = JClass("java.lang.Thread") Runnable = JClass("java.lang.Runnable") Runtime = JClass("java.lang.Runtime") @jpype.JImplements(Runnable) class Run: @jpype.JOverride def run(self): pass th = Thread(Run()) Runtime.getRuntime().addShutdownHook(th) self.assertTrue(Runtime.getRuntime().removeShutdownHook(th)) def testShutdownWrongThread(self): Thread = JClass("java.lang.Thread") Runnable = JClass("java.lang.Runnable") @jpype.JImplements(Runnable) class Run: def __init__(self): self.rc = False @jpype.JOverride def run(self): try: jpype.shutdownJVM() except: self.rc = True run = Run() th = Thread(run) th.start() th.join() self.assertTrue(run.rc) jpype-1.3.0/test/jpypetest/test_coverage.py000066400000000000000000000222201405671516700210660ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import jpype import jpype.imports import common import sys import os import importlib import pytest from unittest import mock import _jpype # Tests just for coverage # These will be moved to the corresponding test file as needed class CoverageCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) self.platform = sys.platform def testWin32(self): if sys.platform == "win32": raise common.unittest.SkipTest("not tested on win32") try: sys.platform = "win32" importlib.reload(jpype._classpath) with self.assertRaises(jpype.JVMNotFoundException): jpype.getDefaultJVMPath() finally: sys.platform = self.platform importlib.reload(jpype._classpath) def testHandleClassPath(self): with self.assertRaises(TypeError): jpype._core._handleClassPath([1]) jpype._core._handleClassPath(["./*.jar"]) def testRestart(self): with self.assertRaises(OSError): jpype.startJVM() def testSynchronizeFail(self): with self.assertRaises(TypeError): jpype.synchronized("hello") def testJArrayFail1(self): with self.assertRaises(TypeError): jpype.JArray(jpype.JInt, 2, 2) def testJArrayFail2(self): with self.assertRaises(TypeError): jpype.JArray(jpype.JInt, 1)(1, 2, 3) def testJArrayStr(self): self.assertEqual(str(jpype.JArray(jpype.JInt)([1, 2])), str([1, 2])) def testJArrayLength(self): ja = jpype.JArray(jpype.JInt)([1, 2]) self.assertEqual(ja.length, len(ja)) def testJArrayGetItemSlice(self): with self.assertRaises(NotImplementedError): ja = jpype.JArray(jpype.JInt)([1, 2, 3, 4]) ja[0:2:-1] def testJArraySetItemSlice(self): ja = jpype.JArray(jpype.JInt)([1, 2, 3, 4, 5, 6]) ja[0:-1:2] = [-1, -1, -1] self.assertEqual(list(ja[:]), [-1, 2, -1, 4, -1, 6]) # FIXME ja[0:-1:2] = [-1] works but should not # FIXME ja[0:-1:2] = 1 gives wierd error def testJArrayGetItemSlice(self): ja = jpype.JArray(jpype.JInt)([1, 2, 3, 4]) ja[1:] def testJArraySetItemSlice(self): ja = jpype.JArray(jpype.JInt)([1, 2, 3, 4]) ja[1:] = [3, 4, 5] self.assertEqual(list(ja[:]), [1, 3, 4, 5]) def testJArrayEQ(self): ja = jpype.JArray(jpype.JInt)([1, 2, 3, 4]) ja == [1, 2] def testJArrayNE(self): ja = jpype.JArray(jpype.JInt)([1, 2, 3, 4]) ja != [1, 2] def testJArrayIter(self): ja = jpype.JArray(jpype.JInt)([1, 2, 3, 4]) for i in ja: pass def testJArrayBytes(self): ja = jpype.JArray(jpype.JByte)([65, 66]) self.assertEqual(str(ja), "AB") def testJArrayBytesFail(self): ja = jpype.JArray(jpype.JByte)([65, 66]) self.assertFalse(ja == None) def testJBooleanFail(self): with self.assertRaises(TypeError): jpype.java.lang.Boolean(1, 2) def testJStringAppend(self): js = jpype.JString("foo") self.assertEqual(js + "bar", "foobar") if not self._convertStrings: self.assertIsInstance(js + "bar", jpype.java.lang.String) def testJStringNE(self): js = jpype.JString("foo") self.assertFalse(js != "foo") self.assertFalse(js != jpype.JString("foo")) # FIXME review this for slices and other cases, we may need # to improve this one def testJStringGetItem(self): js = jpype.JString("fred") self.assertEqual(js[1], "r") def testJStringLen(self): js = jpype.JString("fred") self.assertEqual(len(js), 4) def testJStringLT(self): js = jpype.JString("b") self.assertTrue(js < 'c') self.assertFalse(js < 'b') self.assertFalse(js < 'a') def testJStringLE(self): js = jpype.JString("b") self.assertTrue(js <= 'c') self.assertTrue(js <= 'b') self.assertFalse(js <= 'a') def testJStringGT(self): js = jpype.JString("b") self.assertFalse(js > 'c') self.assertFalse(js > 'b') self.assertTrue(js > 'a') def testJStringGE(self): js = jpype.JString("b") self.assertFalse(js >= 'c') self.assertTrue(js >= 'b') self.assertTrue(js >= 'a') def testJStringContains(self): js = jpype.JString("fred") self.assertTrue("r" in js) self.assertFalse("g" in js) def testJStringRepr(self): js = jpype.JString("fred") self.assertTrue(repr(js), "fred") # def testSetResourceFail(self): # with self.assertRaises(RuntimeError): # _jpype.setResource("NotAResource", None) # FIXME this one is broken # def testJPrimitiveSetAttr(self): # ji = jpype.JInt(1) # with self.assertRaises(AttributeError): # ji.qq = "wow" # FIXME this path seems like something outdated and is not working # def testJBooleanFromBool(self): # self.assertTrue(jpype.java.lang.Boolean(jpype.JInt(40))==True) def testJArrayFail(self): class JArray2(jpype.JArray, internal=True): pass with self.assertRaises(TypeError): JArray2(jpype.JInt) @common.requireInstrumentation def testJStringFail(self): _jpype.fault("PyJPClass_new::verify") class JString2(jpype.JString, internal=True): pass with self.assertRaises(TypeError): JString2("foo") def testCustomizerLate(self): with self.assertRaises(TypeError): @jpype.JImplementationFor("java.lang.Object", base=True) class Sally(object): pass def testCustomizerBadType(self): with self.assertRaises(TypeError): @jpype.JImplementationFor({}) class Sally(object): pass def testModuleHasClass(self): self.assertTrue(_jpype._hasClass("java.lang.Object")) def testJClassBadClass(self): with self.assertRaises(Exception): jpype.JClass("not.a.class") def testJClassBadType(self): with self.assertRaises(TypeError): jpype.JClass({}) def testJClassFromClass(self): self.assertIsInstance(jpype.JClass(jpype.java.lang.Class.forName( "java.lang.StringBuilder")), jpype.JClass) def testHints(self): with self.assertRaises(AttributeError): jpype.JObject._hints = object() @pytest.mark.filterwarnings("ignore::DeprecationWarning") def testDeprecated(self): @jpype._core.deprecated def foo(): pass @jpype._core.deprecated("foo") def bar(): pass bar() foo() def testVersionPreStart(self): with mock.patch('_jpype.isStarted') as func: func.return_value = False self.assertEqual(jpype.getJVMVersion(), (0, 0, 0)) def testGui(self): def foo(): pass # this is executed in a thread which may start later magic = mock.MagicMock() with mock.patch("sys.platform", "other"), mock.patch.dict('sys.modules', {'PyObjCTools': magic}): from PyObjCTools import AppHelper self.assertEqual(sys.platform, "other") jpype.setupGuiEnvironment(foo) self.assertFalse(magic.AppHelper.runConsoleEventLoop.called) jpype.shutdownGuiEnvironment() self.assertFalse(magic.AppHelper.stopEventLoop.called) with mock.patch("sys.platform", "darwin"), mock.patch.dict('sys.modules', {'PyObjCTools': magic}): from PyObjCTools import AppHelper self.assertEqual(sys.platform, "darwin") jpype.setupGuiEnvironment(foo) self.assertTrue(magic.AppHelper.runConsoleEventLoop.called) jpype.shutdownGuiEnvironment() self.assertTrue(magic.AppHelper.stopEventLoop.called) def testImportKey(self): self.assertEqual(jpype.imports._keywordUnwrap("with_"), "with") self.assertEqual(jpype.imports._keywordUnwrap("func"), "func") self.assertEqual(jpype.imports._keywordWrap("with"), "with_") self.assertEqual(jpype.imports._keywordWrap("func"), "func") def testImportNotStarted(self): with mock.patch('_jpype.isStarted') as func: func.return_value = False with self.assertRaisesRegex(ImportError, "jvm"): import mil.spec jpype-1.3.0/test/jpypetest/test_customizer.py000066400000000000000000000031121405671516700214760ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import _jpype import jpype from jpype.types import * from jpype import java import common try: import numpy as np except ImportError: pass class CustomizerTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) self.fixture = JClass('jpype.common.Fixture')() def testSticky(self): @jpype.JImplementationFor("jpype.override.A") class _A: @jpype.JOverride(sticky=True, rename="remove_") def remove(self, obj): pass A = jpype.JClass("jpype.override.A") B = jpype.JClass("jpype.override.B") self.assertEqual(A.remove, _A.remove) self.assertEqual(B.remove, _A.remove) self.assertEqual(str(A.remove_), "jpype.override.A.remove") self.assertEqual(str(B.remove_), "jpype.override.B.remove") jpype-1.3.0/test/jpypetest/test_directbuffer.py000066400000000000000000000130501405671516700217400ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import _jpype import jpype import _jpype from jpype.types import * from jpype import java import common try: import numpy as np except ImportError: pass class JBufferTestCase(common.JPypeTestCase): """ Test for direct buffers. """ def setUp(self): common.JPypeTestCase.setUp(self) self.fixture = JClass('jpype.common.Fixture')() self.bo = JClass("java.nio.ByteOrder") self.cls = JClass("java.nio.ByteBuffer") def testIsDirect(self): obj = self.cls.allocate(10) with self.assertRaises(BufferError): memoryview(obj) obj = self.cls.allocateDirect(10) memoryview(obj) def testReadOnly(self): obj = self.cls.allocateDirect(10).asReadOnlyBuffer() mv = memoryview(obj) self.assertTrue(mv.readonly) def testOrder(self): obj = self.cls.allocateDirect(10) obj.order(self.bo.LITTLE_ENDIAN) v1 = obj.asIntBuffer() self.assertEqual(memoryview(v1).format, 'i') def testMemoryViewByte(self): obj = self.cls.allocateDirect(12) mv = memoryview(obj) self.assertEqual(mv.itemsize, 1) self.assertEqual(mv.strides, (1,)) self.assertEqual(mv.suboffsets, tuple()) self.assertFalse(mv.readonly) self.assertEqual(mv.shape, (12,)) self.assertEqual(mv.format, ">b") def testMemoryViewChar(self): obj = self.cls.allocateDirect(12).asCharBuffer() mv = memoryview(obj) self.assertEqual(mv.itemsize, 2) self.assertEqual(mv.strides, (2,)) self.assertEqual(mv.suboffsets, tuple()) self.assertFalse(mv.readonly) self.assertEqual(mv.shape, (6,)) self.assertEqual(mv.format, ">H") def testMemoryViewShort(self): obj = self.cls.allocateDirect(12).asShortBuffer() mv = memoryview(obj) self.assertEqual(mv.itemsize, 2) self.assertEqual(mv.strides, (2,)) self.assertEqual(mv.suboffsets, tuple()) self.assertFalse(mv.readonly) self.assertEqual(mv.shape, (6,)) self.assertEqual(mv.format, ">h") def testMemoryViewInt(self): obj = self.cls.allocateDirect(12).asIntBuffer() mv = memoryview(obj) self.assertEqual(mv.itemsize, 4) self.assertEqual(mv.strides, (4,)) self.assertEqual(mv.suboffsets, tuple()) self.assertFalse(mv.readonly) self.assertEqual(mv.shape, (3,)) self.assertEqual(mv.format, ">i") def testMemoryViewLong(self): obj = self.cls.allocateDirect(24).asLongBuffer() mv = memoryview(obj) self.assertEqual(mv.itemsize, 8) self.assertEqual(mv.strides, (8,)) self.assertEqual(mv.suboffsets, tuple()) self.assertFalse(mv.readonly) self.assertEqual(mv.shape, (3,)) self.assertEqual(mv.format, ">q") def testMemoryViewFloat(self): obj = self.cls.allocateDirect(24).asFloatBuffer() mv = memoryview(obj) self.assertEqual(mv.itemsize, 4) self.assertEqual(mv.strides, (4,)) self.assertEqual(mv.suboffsets, tuple()) self.assertFalse(mv.readonly) self.assertEqual(mv.shape, (6,)) self.assertEqual(mv.format, ">f") def testMemoryViewDouble(self): obj = self.cls.allocateDirect(24).asDoubleBuffer() mv = memoryview(obj) self.assertEqual(mv.itemsize, 8) self.assertEqual(mv.strides, (8,)) self.assertEqual(mv.suboffsets, tuple()) self.assertFalse(mv.readonly) self.assertEqual(mv.shape, (3,)) self.assertEqual(mv.format, ">d") def checkNP(self, method, dtype, sz): obj = self.cls.allocateDirect(sz * 5) obj.order(self.bo.BIG_ENDIAN) bf = method(obj) mv = np.asarray(memoryview(bf)) ja = JArray(dtype)(5) mv[:] = [1, 2, 3, 4, 5] bf.get(ja) self.assertEqual(list(ja), [1, 2, 3, 4, 5]) obj.order(self.bo.LITTLE_ENDIAN) bf = method(obj) mv = np.asarray(memoryview(bf)) ja = JArray(dtype)(5) mv[:] = [1, 2, 3, 4, 5] bf.get(ja) self.assertEqual(list(ja), [1, 2, 3, 4, 5]) @common.requireNumpy def testMemoryViewShortNP(self): self.checkNP(self.cls.asShortBuffer, JShort, 2) @common.requireNumpy def testMemoryViewIntNP(self): self.checkNP(self.cls.asIntBuffer, JInt, 4) @common.requireNumpy def testMemoryViewLongNP(self): self.checkNP(self.cls.asLongBuffer, JLong, 8) @common.requireNumpy def testMemoryViewFloatNP(self): self.checkNP(self.cls.asFloatBuffer, JFloat, 4) @common.requireNumpy def testMemoryViewDoubleNP(self): self.checkNP(self.cls.asDoubleBuffer, JDouble, 8) jpype-1.3.0/test/jpypetest/test_docstring.py000066400000000000000000000025411405671516700212730ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import jpype import common class DocStringTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) def testDocClass(self): cls = jpype.JClass('java.util.Iterator') self.assertIsNotNone(cls.__doc__) cls = jpype.JClass('java.lang.String') self.assertIsNotNone(cls.__doc__) def testDocMethod(self): cls = jpype.JClass('java.lang.String') self.assertIsNotNone(cls.substring.__doc__) def testDocEnumClass(self): cls = jpype.JClass('java.lang.Character.UnicodeScript') self.assertIsNotNone(cls.__doc__) jpype-1.3.0/test/jpypetest/test_exc.py000066400000000000000000000137121405671516700200600ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import jpype from jpype import JException, java, JProxy, JClass from jpype.types import * import traceback import common def throwIOException(): raise java.io.IOException("Test throw") def throwByJavaException(): JClass('jpype.exc.ExceptionTest').throwIOException() class ExceptionTestCase(common.JPypeTestCase): def testExceptionThrown(self): ext = JClass('jpype.exc.ExceptionTest') try: ext.throwRuntime() self.fail() except JException as ex: self.assertIs(type(ex), java.lang.RuntimeException) self.assertEqual('Foo', ex.message()) trace = ex.stacktrace() self.assertTrue(str(trace).startswith( 'java.lang.RuntimeException: Foo')) def testExceptionByJavaClass(self): ext = JClass('jpype.exc.ExceptionTest') try: ext.throwRuntime() self.fail() except java.lang.RuntimeException as ex: self.assertIs(type(ex), java.lang.RuntimeException) self.assertEqual('Foo', ex.message()) trace = ex.stacktrace() self.assertTrue(str(trace).startswith( 'java.lang.RuntimeException: Foo')) def testThrowException(self): exthrow = JClass('jpype.exc.ExceptionThrower') extest = JClass('jpype.exc.ExceptionTest') d = {"throwIOException": throwIOException, } p = JProxy(exthrow, dict=d) self.assertTrue(extest.delegateThrow(p)) def testThrowException3(self): exthrow = JClass('jpype.exc.ExceptionThrower') extest = JClass('jpype.exc.ExceptionTest') d = {"throwIOException": throwByJavaException, } p = JProxy(exthrow, dict=d) self.assertTrue(extest.delegateThrow(p)) # This test is problematic as __name__ is a class property not an object property # def testExceptionPYEXCName(self): # e = self.jpype.exc.ChildTestException() # name = "jpype.exc.ChildTestException" # self.assertEqual(name, e.__name__) def testExceptionInstanceof(self): e = self.jpype.exc.ChildTestException() self.assertIsInstance(e, self.jpype.exc.ParentTestException) def testExceptionPYEXCInstanceof(self): e = self.jpype.exc.ChildTestException self.assertTrue(issubclass(e, self.jpype.exc.ParentTestException)) def testThrowChildExceptionFromCatchJExceptionParentClass(self): try: self.jpype.exc.ExceptionTest.throwChildTestException() self.fail() except self.jpype.exc.ParentTestException as ex: self.assertIsInstance(ex, self.jpype.exc.ChildTestException) def testCause(self): cls = jpype.JClass("jpype.exc.ExceptionTest") try: cls.throwChain() except Exception as ex: ex1 = ex self.assertEqual(str(ex1.__cause__), "Java Exception") frame = ex1.__cause__.__traceback__ expected = [ 'jpype.exc.ExceptionTest.throwChain', 'jpype.exc.ExceptionTest.method1', 'jpype.exc.ExceptionTest.method2', ] i = 0 while (frame): self.assertEqual(frame.tb_frame.f_code.co_name, expected[i]) frame = frame.tb_next i += 1 def testIndexError(self): with self.assertRaises(IndexError): raise java.lang.IndexOutOfBoundsException("From Java") def testValueError(self): js = JObject(None, JString) with self.assertRaises(ValueError): js.substring(0) def testExcCtor(self): WE = jpype.JClass("jpype.exc.WierdException") with self.assertRaises(WE): WE.testThrow() try: WE.testThrow() except Exception as ex: ex1 = ex self.assertEqual(ex1.args, ("Got it",)) def testExcCauseChained1(self): import jpype.imports try: from org.jpype.fail import BadInitializer except Exception as ex: ex1 = ex self.assertIsInstance(ex1, ImportError) self.assertIsInstance(ex1.__cause__, JClass( "java.lang.ExceptionInInitializerError")) self.assertIsInstance(ex1.__cause__.__cause__, JClass( "java.lang.ArrayIndexOutOfBoundsException")) self.assertTrue(ex1.__cause__.__traceback__ is not None) self.assertTrue(ex1.__cause__.__cause__.__traceback__ is not None) def testExcCauseChained2(self): try: JClass('org.jpype.fail.BadInitializer2') except Exception as ex: ex1 = ex self.assertIsInstance(ex1, JClass( 'java.lang.ExceptionInInitializerError')) self.assertIsInstance(ex1.__cause__.__cause__, JClass( "java.lang.ArrayIndexOutOfBoundsException")) self.assertTrue(ex1.__cause__.__traceback__ is not None) self.assertTrue(ex1.__cause__.__cause__.__traceback__ is not None) def testExpandStacktrace(self): Th = jpype.JClass('java.lang.Throwable') null = jpype.JObject(None, Th) # The next line should not fail Th._expandStacktrace(null) def testException(self): Th = jpype.JClass('java.lang.Throwable')('abc') self.assertEqual(str(Th), 'java.lang.Throwable: abc') jpype-1.3.0/test/jpypetest/test_fault.py000066400000000000000000001377021405671516700204220ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import _jpype import jpype from jpype import * import common class FaultTestCase(common.JPypeTestCase): """ Test for fault paths in JPype This test is only executed if fault instrumentation is compiled in. Fault instrumentation is trigger as part of the coverage compilation. This test suite brutally tries to force an exception to be thrown at each entry point and function call. The exception is controlled based on the name of the function in the JP_TRACE_IN and JP_PY_TRY block. Specific fault points are also triggered to produce abnormal objects which can then be passed to trigger error handling behaviors for off normal conditions. Most of the time the correct response to a fault is to pass it back to the user. But there are two exception to this rule. Function in which a Java resource is released using a Release* method must not fault because these calls can occur during exception handling routines and throwing may trigger an abort. Second, Python calls to free, finalize, and dealloc are not allowed to propagate exceptions as this would potentially interrupt the GC or prevent a object from being freed. Exceptions during the destructor path should be eaten or they may trigger randomly in places the user can't control (assigning a variable, leaving a scope). Many of these tests will be moved to other test units so that they are located with rest of the tests for that unit. Tests that test for something other than SystemError should be separated from the rest of the fault test. This may be one of the most tedious files every written by human hands. Coffee is advised. """ def setUp(self): common.JPypeTestCase.setUp(self) @common.requireInstrumentation def testJPArray_new(self): _jpype.fault("PyJPArray_new") with self.assertRaisesRegex(SystemError, "fault"): JArray(JInt)(5) # FIXME investigate why the release is not happening # may indicate a leak. Disabling for now @common.unittest.SkipTest def testJPArray_releaseBuffer(self): _jpype.fault("PyJPArray_releaseBuffer") def f(): ja = JArray(JInt)(5) m = memoryview(ja) with self.assertRaises(SystemError): f() @common.requireInstrumentation def testJPObject_null(self): Fixture = JClass("jpype.common.Fixture") _jpype.fault("PyJPObject_init.null") null = Fixture() with self.assertRaisesRegex(TypeError, 'Not a Java value'): str(null) self.assertEqual(hash(null), hash(None)) with self.assertRaisesRegex(AttributeError, 'requires'): print(null.int_field) with self.assertRaisesRegex(AttributeError, 'requires'): null.int_field = 1 # null.callInt(1) @common.requireInstrumentation def testJPClass_new(self): _jpype.fault("PyJPClass_new") with self.assertRaisesRegex(SystemError, "fault"): _jpype._JClass("foo", (object,), {}) with self.assertRaises(TypeError): _jpype._JClass("foo", (object,), {}) with self.assertRaises(TypeError): _jpype._JClass("foo", (_jpype._JObject,), {'__del__': None}) @common.requireInstrumentation def testJPClass_init(self): _jpype.fault("PyJPClass_init") with self.assertRaises(SystemError): _jpype._JClass("foo", (_jpype._JObject,), {}, internal=True) with self.assertRaises(TypeError): _jpype._JClass("foo", (object,), {}) _jpype._JClass("foo", (_jpype._JObject,), {}, internal=True) @common.requireInstrumentation def testJPClass_getattro(self): js = JClass("java.lang.String") _jpype.fault("PyJPClass_getattro") with self.assertRaisesRegex(SystemError, "fault"): js.foo with self.assertRaises(TypeError): getattr(js, object()) _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): js.substring @common.requireInstrumentation def testJPClass_setattro(self): js = JClass("java.lang.String") _jpype.fault("PyJPClass_setattro") with self.assertRaisesRegex(SystemError, "fault"): js.substring = 1 with self.assertRaises(TypeError): setattr(js, object(), 1) with self.assertRaises(AttributeError): js.substring = None _jpype.fault("PyJPModule_getContext") with self.assertRaises(SystemError): js.substring = 1 @common.requireInstrumentation def testJPClass_subclasscheck(self): js = JClass("java.lang.String") _jpype.fault("PyJPClass_subclasscheck") with self.assertRaisesRegex(SystemError, "fault"): issubclass(js, JObject) _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): issubclass(js, JObject) @common.requireInstrumentation def testJPClass_class(self): js = JClass("java.lang.String") _jpype.fault("PyJPClass_class") with self.assertRaisesRegex(SystemError, "fault"): js.class_ with self.assertRaises(AttributeError): _jpype._JClass("foo", (_jpype.JObject,), {}, internal=True).class_ _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): js.class_ @common.requireInstrumentation def testJPClass_setClass(self): js = JClass("java.lang.String") _jpype.fault("PyJPClass_setClass") with self.assertRaisesRegex(SystemError, "fault"): js.class_ = None with self.assertRaises(TypeError): js.class_ = None with self.assertRaises(TypeError): js.class_ = JObject() _jpype.fault("PyJPModule_getContext") with self.assertRaises(SystemError): js.class_ = None @common.requireInstrumentation def testJPClass_hints(self): js = JClass("java.lang.String") _jpype.fault("PyJPClass_hints") with self.assertRaisesRegex(SystemError, "fault"): js._hints _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): js._hints self.assertIsInstance(js._hints, _jpype._JClassHints) @common.requireInstrumentation def testJPClass_setHints(self): js = JClass("java.lang.String") _jpype.fault("PyJPClass_setHints") with self.assertRaisesRegex(SystemError, "fault"): js._hints = None @common.requireInstrumentation def testJPClass_cnaConvertToJava(self): js = JClass("java.lang.String") _jpype.fault("PyJPClass_canConvertToJava") with self.assertRaisesRegex(SystemError, "fault"): js._canConvertToJava("f") _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): js._canConvertToJava("f") js._canConvertToJava("f") @common.requireInstrumentation def testJPClass_cast(self): js = JClass("java.lang.String") _jpype.fault("PyJPClass_cast") with self.assertRaisesRegex(SystemError, "fault"): js._cast("f") with self.assertRaises(TypeError): js._cast(object()) _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): js._cast(JObject(None)) js._cast(JObject(None)) @common.requireInstrumentation def testJPClass_convertToJava(self): js = JClass("java.lang.String") _jpype.fault("PyJPClass_convertToJava") with self.assertRaisesRegex(SystemError, "fault"): js._convertToJava("f") with self.assertRaises(TypeError): js._convertToJava(object()) _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): js._convertToJava("f") js._convertToJava("f") @common.requireInstrumentation def testJPClassHints_new(self): _jpype.fault("PyJPClassHints_new") with self.assertRaisesRegex(SystemError, "fault"): _jpype._JClassHints() _jpype._JClassHints() @common.requireInstrumentation def testJPClassHints_init(self): _jpype.fault("PyJPClassHints_init") with self.assertRaisesRegex(SystemError, "fault"): _jpype._JClassHints() _jpype._JClassHints() @common.requireInstrumentation def testJPClassHints_str(self): _jpype.fault("PyJPClassHints_str") with self.assertRaisesRegex(SystemError, "fault"): str(_jpype._JClassHints()) str(_jpype._JClassHints()) @common.requireInstrumentation def testJPClassHints_addAttributeConversion(self): _jpype.fault("PyJPClassHints_addAttributeConversion") with self.assertRaisesRegex(SystemError, "fault"): _jpype._JClassHints()._addAttributeConversion("f", None) def f(): pass with self.assertRaises(TypeError): _jpype._JClassHints()._addAttributeConversion(None, f) with self.assertRaises(TypeError): _jpype._JClassHints()._addAttributeConversion("f", None) _jpype._JClassHints()._addAttributeConversion("f", f) @common.requireInstrumentation def testJPClassHints_addTypeConversion(self): _jpype.fault("PyJPClassHints_addTypeConversion") with self.assertRaisesRegex(SystemError, "fault"): _jpype._JClassHints()._addTypeConversion("f", None) def f(): pass # with self.assertRaises(TypeError): # _jpype._JClassHints()._addTypeConversion(None, f, 1) with self.assertRaises(TypeError): _jpype._JClassHints()._addTypeConversion(str, None, 1) _jpype._JClassHints()._addTypeConversion(str, f, 1) # pyjp_module.cpp: JP_PY_TRY("Py_GetAttrDescriptor"); # pyjp_module.cpp: JP_PY_TRY("PyJPModule_newArrayType"); # pyjp_module.cpp: JP_PY_TRY("PyJPModule_getClass"); # pyjp_module.cpp: JP_PY_TRY("PyJPModule_setClass"); # pyjp_module.cpp: JP_PY_TRY("examine"); # pyjp_module.cpp: JP_PY_TRY("PyInit__jpype"); @common.requireInstrumentation def testJPMonitor_init(self): jo = JClass("java.lang.Object")() _jpype.fault("PyJPMonitor_init") with self.assertRaisesRegex(SystemError, "fault"): _jpype._JMonitor(jo) _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): _jpype._JMonitor(jo) _jpype._JMonitor(jo) @common.requireInstrumentation def testJPMonitor_str(self): jo = JClass("java.lang.Object")() jm = _jpype._JMonitor(jo) _jpype.fault("PyJPMonitor_str") with self.assertRaisesRegex(SystemError, "fault"): str(jm) @common.requireInstrumentation def testJPMonitor_enter(self): jo = JClass("java.lang.Object")() _jpype.fault("PyJPMonitor_enter") with self.assertRaisesRegex(SystemError, "fault"): with _jpype._JMonitor(jo): pass _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): with _jpype._JMonitor(jo): pass @common.requireInstrumentation def testJPMonitor_exit(self): jo = JClass("java.lang.Object")() _jpype.fault("PyJPMonitor_exit") with self.assertRaisesRegex(SystemError, "fault"): with _jpype._JMonitor(jo): pass @common.requireInstrumentation def testJPObject_new(self): _jpype.fault("PyJPObject_new") with self.assertRaisesRegex(SystemError, "fault"): JString("a") _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): JString("a") with self.assertRaises(TypeError): _jpype._JObject() JString("a") @common.requireInstrumentation def testJPObject_hash(self): jo = JClass("java.lang.Object")() _jpype.fault("PyJPObject_hash") with self.assertRaises(SystemError): hash(jo) _jpype.fault("PyJPModule_getContext") with self.assertRaises(SystemError): hash(jo) hash(jo) @common.requireInstrumentation def testJPProxy_new(self): _jpype.fault("PyJPProxy_new") with self.assertRaisesRegex(SystemError, "fault"): JProxy("java.io.Serializable", dict={}) with self.assertRaises(TypeError): _jpype._JProxy(None, None) with self.assertRaises(TypeError): _jpype._JProxy(None, []) with self.assertRaises(TypeError): _jpype._JProxy(None, [type]) _jpype.fault("JPProxy::JPProxy") with self.assertRaises(SystemError): _jpype._JProxy(None, [JClass("java.io.Serializable")]) _jpype._JProxy(None, [JClass("java.io.Serializable")]) # FIXME this needs special treatment. It should call __str__() # if toString is not defined. Disable for now. @common.unittest.SkipTest def testJPProxy_str(self): # Java has a hidden requirement that toString be available @JImplements("java.util.function.DoubleUnaryOperator") class f(object): @JOverride def applyAsDouble(self, d): return d jo = JObject(f(), "java.util.function.DoubleUnaryOperator") raise RuntimeError(jo.toString()) @common.requireInstrumentation def testJPProxy_dealloc(self): _jpype.fault("PyJPProxy_dealloc") def f(): _jpype._JProxy(None, [JClass("java.io.Serializable")]) f() @common.requireInstrumentation def testJPProxy_call(self): @JImplements("java.util.function.DoubleUnaryOperator") class f(object): @JOverride def applyAsDouble(self, d): if d == 2: return None return d _jpype.fault("JPProxy::getProxy") with self.assertRaises(SystemError): JObject(f(), "java.util.function.DoubleUnaryOperator") jo = JObject(f(), "java.util.function.DoubleUnaryOperator") with self.assertRaises(TypeError): jo.applyAsDouble(2) def testJPProxy_void(self): @JImplements("java.util.function.Consumer") class f(object): @JOverride def accept(self, d): return None jo = JObject(f(), "java.util.function.Consumer") jo.accept(None) @common.requireInstrumentation def testJPProxy_void(self): @JImplements("java.util.function.Consumer") class f(object): @JOverride def accept(self, d): return None jo = JObject(f(), "java.util.function.Consumer") _jpype.fault("JPProxy::getArgs") jo.accept(None) @common.requireInstrumentation def testJPProxy_box_return(self): q = None @JImplements("java.util.function.Supplier") class f(object): @JOverride def get(self): return q jo = JObject(f(), "java.util.function.Supplier") self.assertEqual(jo.get(), None) q = 1.0 self.assertIsInstance(jo.get(), java.lang.Double) q = 1 self.assertIsInstance(jo.get(), java.lang.Long) q = "ABC" self.assertIsInstance(jo.get(), java.lang.String) q = object() with self.assertRaises(TypeError): jo.get() @common.requireInstrumentation def testJPValue_alloc(self): _jpype.fault("PyJPValue_alloc") with self.assertRaisesRegex(SystemError, "fault"): JInt(1) _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): JInt(1) JInt(1) @common.requireInstrumentation def testJPValue_finalize(self): _jpype.fault("PyJPValue_finalize") a = JInt(1) del a # lgtm [py/unnecessary-delete] @common.requireInstrumentation def testJPValue_str(self): js = JString("f") _jpype.fault("PyJPValue_str") with self.assertRaisesRegex(SystemError, "fault"): str(js) _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): str(js) str(js) @common.requireInstrumentation def testJPObject_getattro(self): jo = JString("f") _jpype.fault("PyJPObject_getattro") with self.assertRaisesRegex(SystemError, "fault"): jo.substring _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): jo.substring jo.substring @common.requireInstrumentation def testJPObject_setattro(self): jo = JString("f") _jpype.fault("PyJPObject_setattro") with self.assertRaisesRegex(SystemError, "fault"): jo.substring = None @common.requireInstrumentation def testJPField(self): jf = JClass("jpype.common.Fixture") jfi = jf() with self.assertRaises(AttributeError): jf.final_static_int_field = 2 with self.assertRaises(AttributeError): jfi.final_int_field = 2 _jpype.fault("JPField::setStaticAttribute") with self.assertRaisesRegex(SystemError, "fault"): jf.static_int_field = 2 _jpype.fault("JPField::setAttribute") with self.assertRaisesRegex(SystemError, "fault"): jfi.int_field = 2 _jpype.fault("JPField::getStaticAttribute") with self.assertRaisesRegex(SystemError, "fault"): i = jf.static_int_field _jpype.fault("JPField::getAttribute") with self.assertRaisesRegex(SystemError, "fault"): i = jfi.int_field si = jf.__dict__['static_int_field'] str(si) repr(si) i = None _jpype.fault("PyJPField_get") with self.assertRaisesRegex(SystemError, "fault"): i = jfi.int_field self.assertEqual(i, None) _jpype.fault("PyJPField_set") with self.assertRaisesRegex(SystemError, "fault"): jfi.int_field = 2 _jpype.fault("PyJPField_repr") with self.assertRaisesRegex(SystemError, "fault"): repr(si) @common.requireInstrumentation def testConvertString(self): _jpype.fault("JPObjectType::canConvertToJava") with self.assertRaisesRegex(SystemError, "fault"): JObject._convertToJava("foo") _jpype.fault("JPConversionString::matches") with self.assertRaisesRegex(SystemError, "fault"): JString._convertToJava("foo") @common.requireInstrumentation def testJPObject(self): jf = JClass("jpype.common.Fixture") jfi = JClass("jpype.common.Fixture")() _jpype.fault("JPClass::setStaticField") with self.assertRaisesRegex(SystemError, "fault"): jf.static_object_field = None _jpype.fault("JPClass::setField") with self.assertRaisesRegex(SystemError, "fault"): jfi.object_field = None i = None _jpype.fault("JPClass::getStaticField") with self.assertRaisesRegex(SystemError, "fault"): i = jf.static_object_field _jpype.fault("JPClass::getField") with self.assertRaisesRegex(SystemError, "fault"): i = jfi.object_field self.assertEqual(i, None) # FIXME this test triggers the wrong fault which normally # indicates a problem in the exception handling path. # AssertionError: "fault" does not match "NULL context in JPRef() # Disabling for now. @common.unittest.SkipTest @common.requireInstrumentation def testJPTypeManagerFindClass(self): ja = JArray(JInt, 2)([[1, 1], [1, 1]]) _jpype.fault("JPTypeManager::findClass") with self.assertRaisesRegex(SystemError, "fault"): memoryview(ja) _jpype.fault("JPTypeManager::findClassByName") with self.assertRaisesRegex(SystemError, "fault"): JClass("foo.bar") jo = JString('a') _jpype.fault("JPTypeManager::findClassForObject") with self.assertRaisesRegex(SystemError, "fault"): jo.substring(0, 1) @common.requireInstrumentation def testJPTypeManagerPopulate(self): _jpype.fault("JPTypeManager::populateMembers") with self.assertRaisesRegex(SystemError, "fault"): JClass("java.math.MathContext") _jpype.fault("JPTypeManager::populateMethod") with self.assertRaisesRegex(SystemError, "fault"): JClass("java.math.MathContext")().getPrecision() JClass("java.math.MathContext") @common.requireInstrumentation def testMethodPack(self): js = JString("a") _jpype.fault("JPMethod::packArgs") with self.assertRaisesRegex(SystemError, "fault"): js.substring(1) @common.requireInstrumentation def testJBoxedGetJavaConversion(self): _jpype.fault("JPBoxedType::findJavaConversion") with self.assertRaisesRegex(SystemError, "fault"): java.lang.Boolean._canConvertToJava(object()) _jpype.fault("JPBoxedType::findJavaConversion") with self.assertRaisesRegex(SystemError, "fault"): java.lang.Character._canConvertToJava(object()) _jpype.fault("JPBoxedType::findJavaConversion") with self.assertRaisesRegex(SystemError, "fault"): java.lang.Byte._canConvertToJava(object()) _jpype.fault("JPBoxedType::findJavaConversion") with self.assertRaisesRegex(SystemError, "fault"): java.lang.Short._canConvertToJava(object()) _jpype.fault("JPBoxedType::findJavaConversion") with self.assertRaisesRegex(SystemError, "fault"): java.lang.Integer._canConvertToJava(object()) _jpype.fault("JPBoxedType::findJavaConversion") with self.assertRaisesRegex(SystemError, "fault"): java.lang.Long._canConvertToJava(object()) _jpype.fault("JPBoxedType::findJavaConversion") with self.assertRaisesRegex(SystemError, "fault"): java.lang.Float._canConvertToJava(object()) _jpype.fault("JPBoxedType::findJavaConversion") with self.assertRaisesRegex(SystemError, "fault"): java.lang.Double._canConvertToJava(object()) @common.requireInstrumentation def testJPJavaFrame(self): _jpype.fault("JPJavaFrame::JPJavaFrame::NewObjectA") with self.assertRaisesRegex(SystemError, "fault"): raise SystemError("fault") _jpype.fault("JPJavaFrame::JPJavaFrame::NewObject") with self.assertRaisesRegex(SystemError, "fault"): raise SystemError("fault") _jpype.fault("JPJavaFrame::NewDirectByteBuffer") with self.assertRaisesRegex(SystemError, "fault"): raise SystemError("fault") _jpype.fault("JPJavaFrame::GetPrimitiveArrayCritical") with self.assertRaisesRegex(SystemError, "fault"): raise SystemError("fault") _jpype.fault("JPJavaFrame::ReleasePrimitiveArrayCritical") with self.assertRaisesRegex(SystemError, "fault"): raise SystemError("fault") @common.requireInstrumentation def testJPJavaFrameByteField(self): fields = JClass("jpype.common.Fixture")() _jpype.fault("JPJavaFrame::GetStaticByteField") with self.assertRaisesRegex(SystemError, "fault"): print(fields.static_byte_field) _jpype.fault("JPJavaFrame::GetByteField") with self.assertRaisesRegex(SystemError, "fault"): print(fields.byte_field) _jpype.fault("JPJavaFrame::SetStaticByteField") with self.assertRaisesRegex(SystemError, "fault"): fields.static_byte_field = 1 _jpype.fault("JPJavaFrame::SetByteField") with self.assertRaisesRegex(SystemError, "fault"): fields.byte_field = 0 @common.requireInstrumentation def testJPJavaFrameByteMethods(self): cls = JClass("jpype.common.Fixture") obj = cls() _jpype.fault("JPJavaFrame::CallStaticByteMethodA") with self.assertRaisesRegex(SystemError, "fault"): cls.getStaticByte() _jpype.fault("JPJavaFrame::CallByteMethodA") with self.assertRaisesRegex(SystemError, "fault"): obj.getByte() _jpype.fault("JPJavaFrame::CallNonvirtualByteMethodA") with self.assertRaisesRegex(SystemError, "fault"): cls.getByte(obj) @common.requireInstrumentation def testJPJavaFrameShortField(self): fields = JClass("jpype.common.Fixture")() _jpype.fault("JPJavaFrame::GetStaticShortField") with self.assertRaisesRegex(SystemError, "fault"): print(fields.static_short_field) _jpype.fault("JPJavaFrame::GetShortField") with self.assertRaisesRegex(SystemError, "fault"): print(fields.short_field) _jpype.fault("JPJavaFrame::SetStaticShortField") with self.assertRaisesRegex(SystemError, "fault"): fields.static_short_field = 1 _jpype.fault("JPJavaFrame::SetShortField") with self.assertRaisesRegex(SystemError, "fault"): fields.short_field = 1 @common.requireInstrumentation def testJPJavaFrameShortMethod(self): cls = JClass("jpype.common.Fixture") obj = cls() _jpype.fault("JPJavaFrame::CallStaticShortMethodA") with self.assertRaisesRegex(SystemError, "fault"): cls.getStaticShort() _jpype.fault("JPJavaFrame::CallShortMethodA") with self.assertRaisesRegex(SystemError, "fault"): obj.getShort() _jpype.fault("JPJavaFrame::CallNonvirtualShortMethodA") with self.assertRaisesRegex(SystemError, "fault"): cls.getShort(obj) @common.requireInstrumentation def testJPJavaFrameIntField(self): fields = JClass("jpype.common.Fixture")() _jpype.fault("JPJavaFrame::GetStaticIntField") with self.assertRaisesRegex(SystemError, "fault"): print(fields.static_int_field) _jpype.fault("JPJavaFrame::GetIntField") with self.assertRaisesRegex(SystemError, "fault"): print(fields.int_field) _jpype.fault("JPJavaFrame::SetStaticIntField") with self.assertRaisesRegex(SystemError, "fault"): fields.static_int_field = 1 _jpype.fault("JPJavaFrame::SetIntField") with self.assertRaisesRegex(SystemError, "fault"): fields.int_field = 1 @common.requireInstrumentation def testJPJavaFrameIntMethod(self): cls = JClass("jpype.common.Fixture") obj = cls() _jpype.fault("JPJavaFrame::CallStaticIntMethodA") with self.assertRaisesRegex(SystemError, "fault"): cls.getStaticInt() _jpype.fault("JPJavaFrame::CallIntMethodA") with self.assertRaisesRegex(SystemError, "fault"): obj.getInt() _jpype.fault("JPJavaFrame::CallNonvirtualIntMethodA") with self.assertRaisesRegex(SystemError, "fault"): cls.getInt(obj) @common.requireInstrumentation def testJPJavaFrameLongField(self): fields = JClass("jpype.common.Fixture")() _jpype.fault("JPJavaFrame::GetStaticLongField") with self.assertRaisesRegex(SystemError, "fault"): print(fields.static_long_field) _jpype.fault("JPJavaFrame::GetLongField") with self.assertRaisesRegex(SystemError, "fault"): print(fields.long_field) _jpype.fault("JPJavaFrame::SetStaticLongField") with self.assertRaisesRegex(SystemError, "fault"): fields.static_long_field = 1 _jpype.fault("JPJavaFrame::SetLongField") with self.assertRaisesRegex(SystemError, "fault"): fields.long_field = 1 @common.requireInstrumentation def testJPJavaFrameLongMethod(self): cls = JClass("jpype.common.Fixture") obj = cls() _jpype.fault("JPJavaFrame::CallStaticLongMethodA") with self.assertRaisesRegex(SystemError, "fault"): cls.getStaticLong() _jpype.fault("JPJavaFrame::CallLongMethodA") with self.assertRaisesRegex(SystemError, "fault"): obj.getLong() _jpype.fault("JPJavaFrame::CallNonvirtualLongMethodA") with self.assertRaisesRegex(SystemError, "fault"): cls.getLong(obj) @common.requireInstrumentation def testJPJavaFrameFloatField(self): fields = JClass("jpype.common.Fixture")() _jpype.fault("JPJavaFrame::GetStaticFloatField") with self.assertRaisesRegex(SystemError, "fault"): print(fields.static_float_field) _jpype.fault("JPJavaFrame::GetFloatField") with self.assertRaisesRegex(SystemError, "fault"): print(fields.float_field) _jpype.fault("JPJavaFrame::SetStaticFloatField") with self.assertRaisesRegex(SystemError, "fault"): fields.static_float_field = 1 _jpype.fault("JPJavaFrame::SetFloatField") with self.assertRaisesRegex(SystemError, "fault"): fields.float_field = 1 @common.requireInstrumentation def testJPJavaFrameFloatMethod(self): cls = JClass("jpype.common.Fixture") obj = cls() _jpype.fault("JPJavaFrame::CallStaticFloatMethodA") with self.assertRaisesRegex(SystemError, "fault"): cls.getStaticFloat() _jpype.fault("JPJavaFrame::CallFloatMethodA") with self.assertRaisesRegex(SystemError, "fault"): obj.getFloat() _jpype.fault("JPJavaFrame::CallNonvirtualFloatMethodA") with self.assertRaisesRegex(SystemError, "fault"): cls.getFloat(obj) @common.requireInstrumentation def testJPJavaFrameDoubleField(self): fields = JClass("jpype.common.Fixture")() _jpype.fault("JPJavaFrame::GetStaticDoubleField") with self.assertRaisesRegex(SystemError, "fault"): print(fields.static_double_field) _jpype.fault("JPJavaFrame::GetDoubleField") with self.assertRaisesRegex(SystemError, "fault"): print(fields.double_field) _jpype.fault("JPJavaFrame::SetStaticDoubleField") with self.assertRaisesRegex(SystemError, "fault"): fields.static_double_field = 1 _jpype.fault("JPJavaFrame::SetDoubleField") with self.assertRaisesRegex(SystemError, "fault"): fields.double_field = 1 @common.requireInstrumentation def testJPJavaFrameDoubleMethod(self): cls = JClass("jpype.common.Fixture") obj = cls() _jpype.fault("JPJavaFrame::CallStaticDoubleMethodA") with self.assertRaisesRegex(SystemError, "fault"): cls.getStaticDouble() _jpype.fault("JPJavaFrame::CallDoubleMethodA") with self.assertRaisesRegex(SystemError, "fault"): obj.getDouble() _jpype.fault("JPJavaFrame::CallNonvirtualDoubleMethodA") with self.assertRaisesRegex(SystemError, "fault"): cls.getDouble(obj) @common.requireInstrumentation def testJPJavaFrameCharField(self): fields = JClass("jpype.common.Fixture")() _jpype.fault("JPJavaFrame::GetStaticCharField") with self.assertRaisesRegex(SystemError, "fault"): print(fields.static_char_field) _jpype.fault("JPJavaFrame::GetCharField") with self.assertRaisesRegex(SystemError, "fault"): print(fields.char_field) _jpype.fault("JPJavaFrame::SetStaticCharField") with self.assertRaisesRegex(SystemError, "fault"): fields.static_char_field = 1 _jpype.fault("JPJavaFrame::SetCharField") with self.assertRaisesRegex(SystemError, "fault"): fields.char_field = 1 @common.requireInstrumentation def testJPJavaFrameCharMethod(self): cls = JClass("jpype.common.Fixture") obj = cls() _jpype.fault("JPJavaFrame::CallStaticCharMethodA") with self.assertRaisesRegex(SystemError, "fault"): cls.getStaticChar() _jpype.fault("JPJavaFrame::CallCharMethodA") with self.assertRaisesRegex(SystemError, "fault"): obj.getChar() _jpype.fault("JPJavaFrame::CallNonvirtualCharMethodA") with self.assertRaisesRegex(SystemError, "fault"): cls.getChar(obj) @common.requireInstrumentation def testJPJavaFrameBooleanField(self): fields = JClass("jpype.common.Fixture")() _jpype.fault("JPJavaFrame::GetStaticBooleanField") with self.assertRaisesRegex(SystemError, "fault"): print(fields.static_bool_field) _jpype.fault("JPJavaFrame::GetBooleanField") with self.assertRaisesRegex(SystemError, "fault"): print(fields.bool_field) _jpype.fault("JPJavaFrame::SetStaticBooleanField") with self.assertRaisesRegex(SystemError, "fault"): fields.static_bool_field = 1 _jpype.fault("JPJavaFrame::SetBooleanField") with self.assertRaisesRegex(SystemError, "fault"): fields.bool_field = 1 @common.requireInstrumentation def testJPJavaFrameBooleanMethod(self): cls = JClass("jpype.common.Fixture") obj = cls() _jpype.fault("JPJavaFrame::CallStaticBooleanMethodA") with self.assertRaisesRegex(SystemError, "fault"): cls.getStaticBool() _jpype.fault("JPJavaFrame::CallBooleanMethodA") with self.assertRaisesRegex(SystemError, "fault"): obj.getBool() _jpype.fault("JPJavaFrame::CallNonvirtualBooleanMethodA") with self.assertRaisesRegex(SystemError, "fault"): cls.getBool(obj) @common.requireInstrumentation def testJPJavaFrameObjectField(self): fields = JClass("jpype.common.Fixture")() _jpype.fault("JPJavaFrame::GetStaticObjectField") with self.assertRaisesRegex(SystemError, "fault"): print(fields.static_object_field) _jpype.fault("JPJavaFrame::GetObjectField") with self.assertRaisesRegex(SystemError, "fault"): print(fields.object_field) _jpype.fault("JPJavaFrame::SetStaticObjectField") with self.assertRaisesRegex(SystemError, "fault"): fields.static_object_field = None _jpype.fault("JPJavaFrame::SetObjectField") with self.assertRaisesRegex(SystemError, "fault"): fields.object_field = None @common.requireInstrumentation def testJPJavaFrameObjectMethod(self): cls = JClass("jpype.common.Fixture") obj = cls() _jpype.fault("JPJavaFrame::CallStaticObjectMethodA") with self.assertRaisesRegex(SystemError, "fault"): cls.getStaticObject() _jpype.fault("JPJavaFrame::CallObjectMethodA") with self.assertRaisesRegex(SystemError, "fault"): obj.getObject() _jpype.fault("JPJavaFrame::CallNonvirtualObjectMethodA") with self.assertRaisesRegex(SystemError, "fault"): cls.getObject(obj) @common.requireInstrumentation def testJPJavaFrameBooleanArray(self): _jpype.fault("JPJavaFrame::NewBooleanArray") with self.assertRaisesRegex(SystemError, "fault"): JArray(JBoolean)(1) ja = JArray(JBoolean)(5) _jpype.fault("JPJavaFrame::SetBooleanArrayRegion") with self.assertRaisesRegex(SystemError, "fault"): ja[0] = 0 _jpype.fault("JPJavaFrame::GetBooleanArrayRegion") with self.assertRaisesRegex(SystemError, "fault"): print(ja[0]) _jpype.fault("JPJavaFrame::GetBooleanArrayElements") with self.assertRaises(BufferError): memoryview(ja[0:3]) _jpype.fault("JPJavaFrame::ReleaseBooleanArrayElements") with self.assertRaisesRegex(SystemError, "fault"): ja[0:3] = bytes([1, 2, 3]) _jpype.fault("JPJavaFrame::ReleaseBooleanArrayElements") with self.assertRaisesRegex(SystemError, "fault"): jpype.JObject(ja[::2], jpype.JObject) _jpype.fault("JPJavaFrame::ReleaseBooleanArrayElements") def f(): # Special case no fault is allowed memoryview(ja[0:3]) f() @common.requireInstrumentation def testJPJavaFrameMonitor(self): jo = JClass("java.lang.Object")() _jpype.fault("JPJavaFrame::MonitorEnter") with self.assertRaisesRegex(SystemError, "fault"): with syncronized(jo): pass _jpype.fault("JPJavaFrame::MonitorExit") with self.assertRaisesRegex(SystemError, "fault"): with syncronized(jo): pass @common.requireInstrumentation def testJPJavaFrameMonitor(self): _jpype.fault("JPJavaFrame::FromReflectedMethod") with self.assertRaisesRegex(SystemError, "fault"): raise SystemError("fault") _jpype.fault("JPJavaFrame::FromReflectedField") with self.assertRaisesRegex(SystemError, "fault"): raise SystemError("fault") _jpype.fault("JPJavaFrame::FindClass") with self.assertRaisesRegex(SystemError, "fault"): raise SystemError("fault") @common.requireInstrumentation def testJPJavaFrameObjectArray(self): _jpype.fault("JPJavaFrame::NewObjectArray") with self.assertRaisesRegex(SystemError, "fault"): JArray(JObject)(1) ja = JArray(JObject)(1) _jpype.fault("JPJavaFrame::SetObjectArrayElement") with self.assertRaisesRegex(SystemError, "fault"): ja[0] = None _jpype.fault("JPJavaFrame::GetObjectArrayElement") with self.assertRaisesRegex(SystemError, "fault"): print(ja[0]) @common.requireInstrumentation def testJPJavaFrameVoidMethod(self): _jpype.fault("JPJavaFrame::CallStaticVoidMethodA") with self.assertRaisesRegex(SystemError, "fault"): raise SystemError("fault") _jpype.fault("JPJavaFrame::CallVoidMethodA") with self.assertRaisesRegex(SystemError, "fault"): raise SystemError("fault") _jpype.fault("JPJavaFrame::CallVoidMethodA") with self.assertRaisesRegex(SystemError, "fault"): raise SystemError("fault") _jpype.fault("None") @common.requireInstrumentation def testJPJavaFrameAssignable(self): _jpype.fault("JPJavaFrame::IsAssignableFrom") with self.assertRaisesRegex(SystemError, "fault"): issubclass(JString, JObject) @common.requireInstrumentation def testJPJavaFrameString(self): _jpype.fault("JPJavaFrame::NewString") with self.assertRaisesRegex(SystemError, "fault"): JString("aa") _jpype.fault("JPJavaFrame::GetStringUTFChars") with self.assertRaisesRegex(SystemError, "fault"): str(JString("a")) _jpype.fault("JPJavaFrame::ReleaseStringUTFChars") # Releas must not pass the exception because it would # cause an abort. str(JString("a")) _jpype.fault("JPJavaFrame::GetStringUTFLength") with self.assertRaisesRegex(SystemError, "fault"): str(JString("a")) @common.requireInstrumentation def testJPJavaFrameArrayLength(self): _jpype.fault("JPJavaFrame::GetArrayLength") with self.assertRaisesRegex(SystemError, "fault"): JArray(JInt)(5) # These are very hard to hit as they are all startup routines # _jpype.fault("JPJavaFrame::GetMethodID") # with self.assertRaisesRegex(SystemError, "fault"): # raise SystemError("fault") # _jpype.fault("JPJavaFrame::GetStaticMethodID") # with self.assertRaisesRegex(SystemError, "fault"): # raise SystemError("fault") # _jpype.fault("JPJavaFrame::GetFieldID") # with self.assertRaisesRegex(SystemError, "fault"): # raise SystemError("fault") # _jpype.fault("JPJavaFrame::DefineClass") # with self.assertRaisesRegex(SystemError, "fault"): # raise SystemError("fault") # _jpype.fault("JPJavaFrame::RegisterNatives") # with self.assertRaisesRegex(SystemError, "fault"): # raise SystemError("fault") @common.requireInstrumentation def testJPClassTypeGetJavaConversion(self): jc = JClass("java.lang.StringBuilder") _jpype.fault("JPClass::findJavaConversion") with self.assertRaisesRegex(SystemError, "fault"): jc._canConvertToJava(object()) @jpype.JConversion("java.lang.StringBuilder", exact=object) def f(self, obj): raise SystemError("fail") with self.assertRaisesRegex(SystemError, "fail"): jc._convertToJava(object()) @common.requireInstrumentation def testStartup(self): _jpype.fault("PyJPModule_startup") with self.assertRaisesRegex(SystemError, "fault"): _jpype.startup() @common.requireInstrumentation def testShutdown(self): _jpype.fault("PyJPModule_shutdown") with self.assertRaisesRegex(SystemError, "fault"): _jpype.shutdown() @common.requireInstrumentation def testAttachThread(self): _jpype.fault("PyJPModule_attachThread") with self.assertRaisesRegex(SystemError, "fault"): _jpype.attachThreadToJVM() @common.requireInstrumentation def testAttachThreadAsDaemon(self): _jpype.fault("PyJPModule_attachThreadAsDaemon") with self.assertRaisesRegex(SystemError, "fault"): _jpype.attachThreadAsDaemon() @common.requireInstrumentation def testDetachThreadFault(self): _jpype.fault("PyJPModule_detachThread") with self.assertRaisesRegex(SystemError, "fault"): _jpype.detachThreadFromJVM() def testDetachThread(self): self.assertTrue(_jpype.isThreadAttachedToJVM()) _jpype.detachThreadFromJVM() self.assertFalse(_jpype.isThreadAttachedToJVM()) _jpype.attachThreadToJVM() @common.requireInstrumentation def testIsThreadAttached(self): _jpype.fault("PyJPModule_isThreadAttached") with self.assertRaisesRegex(SystemError, "fault"): _jpype.isThreadAttachedToJVM() @common.requireInstrumentation def testConvertToDirectBufferFault(self): _jpype.fault("PyJPModule_convertToDirectByteBuffer") with self.assertRaisesRegex(SystemError, "fault"): _jpype.convertToDirectBuffer(1) def testConvertToDirectBufferExc(self): with self.assertRaisesRegex(TypeError, "buffer support"): _jpype.convertToDirectBuffer(1) with self.assertRaisesRegex(BufferError, "not writable"): _jpype.convertToDirectBuffer(bytes([1, 2, 3])) def testStartupBadArg(self): with self.assertRaisesRegex(TypeError, "takes exactly"): _jpype.startup() with self.assertRaisesRegex(TypeError, "must be tuple"): _jpype.startup(object(), object(), True, True, True) with self.assertRaisesRegex(TypeError, "must be strings"): _jpype.startup("", (object(),), True, True, True) with self.assertRaisesRegex(TypeError, "must be a string"): _jpype.startup(object(), tuple(), True, True, True) with self.assertRaisesRegex(OSError, "started"): _jpype.startup("", tuple(), True, True, True) def testGetClass(self): with self.assertRaisesRegex(TypeError, "not found"): _jpype._getClass("not.a.class") def testHasClass(self): with self.assertRaisesRegex(TypeError, "not found"): _jpype._hasClass("not.a.class") with self.assertRaisesRegex(TypeError, "str is required"): _jpype._hasClass(object()) def testArrayFromBuffer(self): with self.assertRaisesRegex(TypeError, "2 arguments"): _jpype.arrayFromBuffer() with self.assertRaisesRegex(TypeError, "does not support buffers"): _jpype.arrayFromBuffer(object(), object()) def testArrayNewType(self): with self.assertRaisesRegex(TypeError, "2 arguments"): _jpype._newArrayType() with self.assertRaisesRegex(TypeError, "must be an integer"): _jpype._newArrayType(object(), object()) with self.assertRaisesRegex(TypeError, "class required"): _jpype._newArrayType(object(), 1) @common.requireInstrumentation def testClassHintsFaults(self): class CTest(object): pass @JConversion("java.lang.Number", exact=CTest) def _CTestConversion(jcls, obj): return java.lang.Integer(123) class ATest(object): def __foo__(self): pass @JConversion("java.lang.Number", attribute="__foo__") def _ATestConversion(jcls, obj): return java.lang.Integer(123) fixture = JClass("jpype.common.Fixture")() _jpype.fault("JPPythonConversion::convert") with self.assertRaisesRegex(SystemError, "fault"): fixture.callNumber(CTest()) _jpype.fault("JPAttributeConversion::matches") with self.assertRaisesRegex(SystemError, "fault"): fixture.callNumber(ATest()) _jpype.fault("JPClassHints::addAttributeConversion") with self.assertRaisesRegex(SystemError, "fault"): @JConversion("java.lang.Number", attribute="__woo__") def f(jcls, obj): pass _jpype.fault("JPTypeConversion::matches") with self.assertRaisesRegex(SystemError, "fault"): fixture.callNumber(CTest()) _jpype.fault("JPClassHints::addTypeConversion") with self.assertRaisesRegex(SystemError, "fault"): @JConversion("java.lang.Number", exact=CTest) def f(jcls, obj): pass @common.requireInstrumentation def testConversionFaults(self): fixture = JClass("jpype.common.Fixture")() _jpype.fault("JPConversionCharArray::matches") with self.assertRaisesRegex(SystemError, "fault"): fixture.callCharArray(object()) _jpype.fault("JPConversionByteArray::matches") with self.assertRaisesRegex(SystemError, "fault"): fixture.callByteArray(object()) _jpype.fault("JPConversionNull::matches") with self.assertRaisesRegex(SystemError, "fault"): fixture.callObject(None) _jpype.fault("JPConversionClass::matches") with self.assertRaisesRegex(SystemError, "fault"): fixture.callClass(object()) _jpype.fault("JPConversionObject::matches") with self.assertRaisesRegex(SystemError, "fault"): fixture.callObject(object()) _jpype.fault("JPConversionJavaObjectAny::matches") with self.assertRaisesRegex(SystemError, "fault"): fixture.callObject(object()) _jpype.fault("JPConversionJavaNumberAny::matches") with self.assertRaisesRegex(SystemError, "fault"): fixture.callNumber(object()) _jpype.fault("JPConversionString::matches") with self.assertRaisesRegex(SystemError, "fault"): fixture.callString(object()) _jpype.fault("JPConversionBoxBoolean::matches") with self.assertRaisesRegex(SystemError, "fault"): fixture.callObject(object()) _jpype.fault("JPConversionBoxLong::matches") with self.assertRaisesRegex(SystemError, "fault"): fixture.callObject(object()) _jpype.fault("JPConversionBoxDouble::matches") with self.assertRaisesRegex(SystemError, "fault"): fixture.callObject(object()) _jpype.fault("JPConversionProxy::matches") with self.assertRaisesRegex(SystemError, "fault"): fixture.callObject(object()) jpype-1.3.0/test/jpypetest/test_fields.py000066400000000000000000000207071405671516700205510ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import jpype from jpype.types import * from jpype import JPackage, java import common class FieldsTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) self.cls = JClass("jpype.common.Fixture") self.obj = self.cls() def testBoolean(self): self.obj.bool_field = True self.assertTrue(self.obj.bool_field) self.assertTrue(self.obj.getBool()) self.obj.bool_field = False self.assertFalse(self.obj.bool_field) self.assertFalse(self.obj.getBool()) self.obj.static_bool_field = True self.assertTrue(self.obj.static_bool_field) self.assertTrue(self.cls.static_bool_field) self.obj.static_bool_field = False self.assertFalse(self.obj.static_bool_field) self.assertFalse(self.cls.static_bool_field) with self.assertRaises(AttributeError): self.cls.bool_field = True with self.assertRaises(AttributeError): self.cls.bool_field = False self.cls.static_bool_field = True self.assertTrue(self.cls.static_bool_field) self.assertTrue(self.cls.getStaticBool()) self.cls.static_bool_field = False self.assertFalse(self.cls.static_bool_field) self.assertFalse(self.cls.getStaticBool()) def testChar(self): self.obj.char_field = 'Q' self.assertEqual(self.obj.char_field, 'Q') self.assertEqual(self.obj.getChar(), 'Q') self.obj.static_char_field = 'S' self.assertEqual(self.obj.static_char_field, 'S') self.assertEqual(self.cls.static_char_field, 'S') self.assertEqual(self.obj.getStaticChar(), 'S') self.assertEqual(self.cls.getStaticChar(), 'S') with self.assertRaises(AttributeError): self.cls.char_field = 'U' with self.assertRaises(AttributeError): self.cls.char_field = 'V' self.cls.static_char_field = 'W' self.assertEqual(self.cls.static_char_field, 'W') self.assertEqual(self.obj.getStaticChar(), 'W') self.assertEqual(self.cls.getStaticChar(), 'W') def testByte(self): self.obj.byte_field = 34 self.assertEqual(self.obj.byte_field, 34) self.assertEqual(self.obj.getByte(), 34) self.obj.static_byte_field = 36 self.assertEqual(self.obj.static_byte_field, 36) self.assertEqual(self.cls.static_byte_field, 36) self.assertEqual(self.obj.getStaticByte(), 36) self.assertEqual(self.cls.getStaticByte(), 36) with self.assertRaises(AttributeError): self.cls.byte_field = 38 with self.assertRaises(AttributeError): self.cls.byte_field = 39 self.cls.static_byte_field = 40 self.assertEqual(self.cls.static_byte_field, 40) self.assertEqual(self.obj.getStaticByte(), 40) self.assertEqual(self.cls.getStaticByte(), 40) def testShort(self): self.obj.short_field = 34 self.assertEqual(self.obj.short_field, 34) self.assertEqual(self.obj.getShort(), 34) self.obj.static_short_field = 36 self.assertEqual(self.obj.static_short_field, 36) self.assertEqual(self.cls.static_short_field, 36) self.assertEqual(self.obj.getStaticShort(), 36) self.assertEqual(self.cls.getStaticShort(), 36) with self.assertRaises(AttributeError): self.cls.short_field = 38 with self.assertRaises(AttributeError): self.cls.short_field = 39 self.cls.static_short_field = 40 self.assertEqual(self.cls.static_short_field, 40) self.assertEqual(self.obj.getStaticShort(), 40) self.assertEqual(self.cls.getStaticShort(), 40) def testInt(self): self.obj.int_field = 34 self.assertEqual(self.obj.int_field, 34) self.assertEqual(self.obj.getInt(), 34) self.obj.static_int_field = 36 self.assertEqual(self.obj.static_int_field, 36) self.assertEqual(self.cls.static_int_field, 36) self.assertEqual(self.obj.getStaticInt(), 36) self.assertEqual(self.cls.getStaticInt(), 36) with self.assertRaises(AttributeError): self.cls.int_field = 38 with self.assertRaises(AttributeError): self.cls.int_field = 39 self.cls.static_int_field = 40 self.assertEqual(self.cls.static_int_field, 40) self.assertEqual(self.obj.getStaticInt(), 40) self.assertEqual(self.cls.getStaticInt(), 40) def testLong(self): self.obj.long_field = 34 self.assertEqual(self.obj.long_field, 34) self.assertEqual(self.obj.getLong(), 34) self.obj.static_long_field = 36 self.assertEqual(self.obj.static_long_field, 36) self.assertEqual(self.cls.static_long_field, 36) self.assertEqual(self.obj.getStaticLong(), 36) self.assertEqual(self.cls.getStaticLong(), 36) with self.assertRaises(AttributeError): self.cls.long_field = 38 with self.assertRaises(AttributeError): self.cls.long_field = 39 self.cls.static_long_field = 40 self.assertEqual(self.cls.static_long_field, 40) self.assertEqual(self.obj.getStaticLong(), 40) self.assertEqual(self.cls.getStaticLong(), 40) def testFloat(self): self.obj.float_field = 34 self.assertEqual(self.obj.float_field, 34) self.assertEqual(self.obj.getFloat(), 34) self.obj.static_float_field = 36 self.assertEqual(self.obj.static_float_field, 36) self.assertEqual(self.cls.static_float_field, 36) self.assertEqual(self.obj.getStaticFloat(), 36) self.assertEqual(self.cls.getStaticFloat(), 36) with self.assertRaises(AttributeError): self.cls.float_field = 38 with self.assertRaises(AttributeError): self.cls.float_field = 39 self.cls.static_float_field = 40 self.assertEqual(self.cls.static_float_field, 40) self.assertEqual(self.obj.getStaticFloat(), 40) self.assertEqual(self.cls.getStaticFloat(), 40) def testDouble(self): self.obj.double_field = 34 self.assertEqual(self.obj.double_field, 34) self.assertEqual(self.obj.getDouble(), 34) self.obj.static_double_field = 36 self.assertEqual(self.obj.static_double_field, 36) self.assertEqual(self.cls.static_double_field, 36) self.assertEqual(self.obj.getStaticDouble(), 36) self.assertEqual(self.cls.getStaticDouble(), 36) with self.assertRaises(AttributeError): self.cls.double_field = 38 with self.assertRaises(AttributeError): self.cls.double_field = 39 self.cls.static_double_field = 40 self.assertEqual(self.cls.static_double_field, 40) self.assertEqual(self.obj.getStaticDouble(), 40) self.assertEqual(self.cls.getStaticDouble(), 40) def testObject(self): self.obj.object_field = "Alice" self.assertEqual(self.obj.object_field, "Alice") self.assertEqual(self.obj.getObject(), "Alice") self.obj.static_object_field = "Bob" self.assertEqual(self.obj.static_object_field, "Bob") self.assertEqual(self.cls.static_object_field, "Bob") self.assertEqual(self.obj.getStaticObject(), "Bob") self.assertEqual(self.cls.getStaticObject(), "Bob") with self.assertRaises(AttributeError): self.cls.object_field = "Xena" with self.assertRaises(AttributeError): self.cls.object_field = "Gabrielle" self.cls.static_object_field = "Charlie" self.assertEqual(self.cls.static_object_field, "Charlie") self.assertEqual(self.obj.getStaticObject(), "Charlie") self.assertEqual(self.cls.getStaticObject(), "Charlie") jpype-1.3.0/test/jpypetest/test_forname.py000066400000000000000000000032511405671516700207250ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import sys import jpype import common class ForNameTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) def testForName(self): cls = jpype.JClass('java.lang.Class') test = cls.forName('jpype.overloads.Test1') # Should return a java.lang.Class, rather than the python wrapper for java.lang.Class self.assertTrue(type(test) == type(cls.class_)) self.assertEqual(test.getName(), 'jpype.overloads.Test1') def testForName2(self): cls = jpype.JClass('java.lang.Class') clsloader = jpype.JClass( 'java.lang.ClassLoader').getSystemClassLoader() test = cls.forName('jpype.overloads.Test1', True, clsloader) # Should return a java.lang.Class, rather than the python wrapper for java.lang.Class self.assertTrue(type(test) == type(cls.class_)) self.assertEqual(test.getName(), 'jpype.overloads.Test1') jpype-1.3.0/test/jpypetest/test_generic.py000066400000000000000000000033421405671516700207130ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import jpype import common class GenericTestCase(common.JPypeTestCase): """ Test for JClass with generic types """ def setUp(self): common.JPypeTestCase.setUp(self) def testArray0(self): cls = jpype.JClass('java.util.ArrayList<>') def testArray1(self): cls = jpype.JClass('java.util.ArrayList') def testArray2(self): with self.assertRaises(TypeError): cls = jpype.JClass('java.util.ArrayList') def testMap0(self): cls = jpype.JClass('java.util.HashMap<>') def testMap1(self): with self.assertRaises(TypeError): cls = jpype.JClass('java.util.HashMap') def testMap2(self): cls = jpype.JClass('java.util.HashMap') def testObject0(self): with self.assertRaises(TypeError): cls = jpype.JClass('java.lang.Object<>') def testObject1(self): with self.assertRaises(TypeError): cls = jpype.JClass('java.lang.Object') jpype-1.3.0/test/jpypetest/test_hash.py000066400000000000000000000054401405671516700202230ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import jpype import common import sys class HashTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) def testHashString(self): self.assertIsNotNone(hash(jpype.java.lang.String("upside down"))) self.assertIsNotNone(hash(jpype.JString("upside down"))) self.assertEqual(hash(jpype.JString("upside down")), hash("upside down")) def testHashArray(self): self.assertIsNotNone(hash(jpype.JArray(jpype.JInt)([1, 2, 3]))) def testHashObject(self): self.assertIsNotNone(hash(jpype.java.lang.Object())) def testHashBoolean(self): self.assertIsNotNone(hash(jpype.java.lang.Boolean(True))) self.assertEqual(hash(jpype.java.lang.Boolean(True)), hash(True)) def testHashByte(self): self.assertIsNotNone(hash(jpype.java.lang.Byte(5))) self.assertEqual(hash(jpype.java.lang.Byte(5)), hash(5)) def testHashChar(self): self.assertIsNotNone(hash(jpype.java.lang.Character("a"))) # Differences in implementation yield different hashes currently. #self.assertEqual(hash(jpype.java.lang.Character("a")), hash("a")) def testHashShort(self): self.assertIsNotNone(hash(jpype.java.lang.Short(1))) self.assertEqual(hash(jpype.java.lang.Short(1)), hash(1)) def testHashLong(self): self.assertIsNotNone(hash(jpype.java.lang.Long(55))) self.assertEqual(hash(jpype.java.lang.Long(55)), hash(55)) def testHashInteger(self): self.assertIsNotNone(hash(jpype.java.lang.Integer(123))) self.assertEqual(hash(jpype.java.lang.Integer(123)), hash(123)) def testHashFloat(self): self.assertIsNotNone(hash(jpype.java.lang.Float(3.141592))) def testHashDouble(self): self.assertIsNotNone(hash(jpype.java.lang.Double(6.62607004e-34))) def testHashNone(self): self.assertEqual(hash(None), hash(jpype.JObject(None))) q = jpype.JObject(None, jpype.java.lang.Double) self.assertEqual(hash(None), hash(jpype.JObject(None))) jpype-1.3.0/test/jpypetest/test_hints.py000066400000000000000000000436651405671516700204400ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import _jpype import jpype from jpype.types import * import common import jpype.protocol as proto class HintsTestCase(common.JPypeTestCase): def testCache(self): cls = JClass('java.lang.Object') hints = cls._hints hints2 = cls._hints self.assertEqual(hints, hints2) def testProtocol(self): protocol = jpype.protocol.SupportsFloat annot = protocol.__float__.__annotations__ self.assertEqual(annot['return'], float) protocol = jpype.protocol.SupportsIndex annot = protocol.__index__.__annotations__ self.assertEqual(annot['return'], int) self.assertTrue(hasattr(proto, "Sequence")) self.assertTrue(hasattr(proto, "Mapping")) self.assertTrue(hasattr(proto, "Protocol")) def testObject(self): cls = JClass('java.lang.Object') hints = cls._hints self.assertTrue(cls in hints.returns) self.assertTrue(cls in hints.exact) self.assertTrue(str in hints.implicit) self.assertTrue(bool in hints.implicit) self.assertTrue(proto.SupportsIndex in hints.implicit) self.assertTrue(proto.SupportsFloat in hints.implicit) self.assertTrue(proto._JClass in hints.implicit) self.assertTrue(len(hints.explicit) == 0) self.assertTrue(len(hints.none) == 0) def testNumber(self): cls = JClass('java.lang.Number') hints = cls._hints self.assertTrue(cls in hints.returns) self.assertTrue(proto._JNumberLong in hints.implicit) self.assertTrue(proto._JNumberFloat in hints.implicit) self.assertTrue(proto.SupportsIndex in hints.implicit) self.assertTrue(proto.SupportsFloat in hints.implicit) self.assertTrue(len(hints.explicit) == 0) self.assertTrue(len(hints.none) == 0) def testString(self): cls = JClass('java.lang.String') hints = cls._hints self.assertTrue(cls in hints.returns) self.assertTrue(cls in hints.exact) self.assertTrue(str in hints.implicit) self.assertTrue(len(hints.explicit) == 0) self.assertTrue(len(hints.none) == 0) def testClass(self): cls = JClass('java.lang.Class') hints = cls._hints self.assertTrue(cls in hints.returns) self.assertTrue(cls in hints.exact) self.assertTrue(proto._JClass in hints.implicit) self.assertTrue(len(hints.explicit) == 0) self.assertTrue(len(hints.none) == 0) def testCollection(self): cls = JClass('java.util.Collection') hints = cls._hints self.assertTrue(cls in hints.returns) self.assertTrue(cls in hints.exact) self.assertTrue(proto.Sequence in hints.implicit) self.assertTrue(len(hints.explicit) == 0) self.assertTrue(str in hints.none) def testList(self): cls = JClass('java.util.List') hints = cls._hints self.assertTrue(cls in hints.returns) self.assertTrue(cls in hints.exact) self.assertTrue(len(hints.implicit) == 0) self.assertTrue(len(hints.explicit) == 0) self.assertTrue(len(hints.none) == 0) def testJBoolean(self): cls = JBoolean hints = cls._hints self.assertTrue(bool in hints.returns) self.assertTrue(bool in hints.exact) self.assertTrue(cls in hints.exact) self.assertTrue(JClass("java.lang.Boolean") in hints.implicit) self.assertTrue(proto.SupportsIndex in hints.explicit) self.assertTrue(proto.SupportsFloat in hints.explicit) self.assertTrue(len(hints.none) == 0) def testJChar(self): cls = JChar hints = cls._hints self.assertTrue(cls in hints.returns) self.assertTrue(cls in hints.exact) self.assertTrue(JClass("java.lang.Character") in hints.implicit) self.assertTrue(str in hints.implicit) self.assertTrue(len(hints.explicit) == 0) self.assertTrue(len(hints.none) == 0) def testJShort(self): cls = JShort hints = cls._hints self.assertTrue(cls in hints.returns) self.assertTrue(cls in hints.exact) self.assertTrue(JByte in hints.implicit) self.assertTrue(JChar in hints.implicit) self.assertTrue(JClass("java.lang.Short") in hints.implicit) self.assertTrue(proto.SupportsIndex in hints.implicit) self.assertTrue(proto.SupportsFloat in hints.explicit) self.assertTrue(len(hints.none) == 0) def testJInt(self): cls = JInt hints = cls._hints self.assertTrue(cls in hints.returns) self.assertTrue(cls in hints.exact) self.assertTrue(JByte in hints.implicit) self.assertTrue(JChar in hints.implicit) self.assertTrue(JShort in hints.implicit) self.assertTrue(JClass('java.lang.Integer') in hints.implicit) self.assertTrue(proto.SupportsIndex in hints.implicit) self.assertTrue(proto.SupportsFloat in hints.explicit) self.assertTrue(len(hints.none) == 0) def testJLong(self): cls = JLong hints = cls._hints self.assertTrue(cls in hints.returns) self.assertTrue(cls in hints.exact) self.assertTrue(JByte in hints.implicit) self.assertTrue(JChar in hints.implicit) self.assertTrue(JShort in hints.implicit) self.assertTrue(JInt in hints.implicit) self.assertTrue(JClass('java.lang.Long') in hints.implicit) self.assertTrue(proto.SupportsIndex in hints.implicit) self.assertTrue(proto.SupportsFloat in hints.explicit) self.assertTrue(len(hints.none) == 0) def testJFloat(self): cls = JFloat hints = cls._hints self.assertTrue(cls in hints.returns) self.assertTrue(cls in hints.exact) self.assertTrue(JByte in hints.implicit) self.assertTrue(JChar in hints.implicit) self.assertTrue(JShort in hints.implicit) self.assertTrue(JInt in hints.implicit) self.assertTrue(JLong in hints.implicit) self.assertTrue(JClass('java.lang.Float') in hints.implicit) self.assertTrue(int in hints.implicit) self.assertTrue(proto.SupportsIndex in hints.implicit) self.assertTrue(proto.SupportsFloat in hints.implicit) self.assertTrue(len(hints.explicit) == 0) self.assertTrue(len(hints.none) == 0) def testJDouble(self): cls = JDouble hints = cls._hints self.assertTrue(cls in hints.returns) self.assertTrue(cls in hints.exact) self.assertTrue(JByte in hints.implicit) self.assertTrue(JChar in hints.implicit) self.assertTrue(JShort in hints.implicit) self.assertTrue(JInt in hints.implicit) self.assertTrue(JLong in hints.implicit) self.assertTrue(JFloat in hints.implicit) self.assertTrue(JClass('java.lang.Double') in hints.implicit) self.assertTrue(proto.SupportsIndex in hints.implicit) self.assertTrue(proto.SupportsFloat in hints.implicit) self.assertTrue(int in hints.implicit) self.assertTrue(len(hints.explicit) == 0) self.assertTrue(len(hints.none) == 0) def testBoxedByte(self): cls = JClass('java.lang.Byte') hints = cls._hints self.assertTrue(cls in hints.returns) self.assertTrue(cls in hints.exact) self.assertTrue(JByte in hints.implicit) self.assertTrue(proto.SupportsFloat in hints.explicit) self.assertTrue(JClass('java.lang.Byte') in hints.explicit) self.assertTrue(proto.SupportsIndex in hints.explicit) self.assertTrue(len(hints.none) == 0) def testBoxedBoolean(self): cls = JClass('java.lang.Boolean') hints = cls._hints self.assertTrue(cls in hints.returns) self.assertTrue(cls in hints.exact) self.assertTrue(bool in hints.implicit) self.assertTrue(JBoolean in hints.implicit) self.assertTrue(proto.SupportsIndex in hints.explicit) self.assertTrue(proto.SupportsFloat in hints.explicit) self.assertTrue(JClass('java.lang.Boolean') in hints.explicit) self.assertTrue(len(hints.none) == 0) def testBoxedCharacter(self): cls = JClass('java.lang.Character') hints = cls._hints self.assertTrue(cls in hints.returns) self.assertTrue(cls in hints.exact) self.assertTrue(JChar in hints.implicit) self.assertTrue(JClass('java.lang.Character') in hints.explicit) self.assertTrue(str in hints.explicit) self.assertTrue(len(hints.none) == 0) def testBoxedShort(self): cls = JClass('java.lang.Short') hints = cls._hints self.assertTrue(cls in hints.returns) self.assertTrue(cls in hints.exact) self.assertTrue(JShort in hints.implicit) self.assertTrue(proto.SupportsFloat in hints.explicit) self.assertTrue(JByte in hints.explicit) self.assertTrue(JChar in hints.explicit) self.assertTrue(JClass('java.lang.Short') in hints.explicit) self.assertTrue(proto.SupportsIndex in hints.explicit) self.assertTrue(len(hints.none) == 0) def testBoxedInteger(self): cls = JClass('java.lang.Integer') hints = cls._hints self.assertTrue(cls in hints.returns) self.assertTrue(cls in hints.exact) self.assertTrue(JInt in hints.implicit) self.assertTrue(proto.SupportsFloat in hints.explicit) self.assertTrue(JByte in hints.explicit) self.assertTrue(JChar in hints.explicit) self.assertTrue(JShort in hints.explicit) self.assertTrue(JClass('java.lang.Integer') in hints.explicit) self.assertTrue(proto.SupportsIndex in hints.explicit) self.assertTrue(len(hints.none) == 0) def testBoxedLong(self): cls = JClass('java.lang.Long') hints = cls._hints self.assertTrue(cls in hints.returns) self.assertTrue(cls in hints.exact) self.assertTrue(JLong in hints.implicit) self.assertTrue(proto.SupportsFloat in hints.explicit) self.assertTrue(JByte in hints.explicit) self.assertTrue(JChar in hints.explicit) self.assertTrue(JShort in hints.explicit) self.assertTrue(JInt in hints.explicit) self.assertTrue(JClass('java.lang.Long') in hints.explicit) self.assertTrue(proto.SupportsIndex in hints.explicit) self.assertTrue(len(hints.none) == 0) def testBoxedFloat(self): cls = JClass('java.lang.Float') hints = cls._hints self.assertTrue(cls in hints.returns) self.assertTrue(cls in hints.exact) self.assertTrue(JFloat in hints.implicit) self.assertTrue(JByte in hints.explicit) self.assertTrue(JChar in hints.explicit) self.assertTrue(JShort in hints.explicit) self.assertTrue(JInt in hints.explicit) self.assertTrue(JLong in hints.explicit) self.assertTrue(JClass('java.lang.Float') in hints.explicit) self.assertTrue(int in hints.explicit) self.assertTrue(proto.SupportsIndex in hints.explicit) self.assertTrue(proto.SupportsFloat in hints.explicit) self.assertTrue(len(hints.none) == 0) def testBoxedDouble(self): cls = JClass('java.lang.Double') hints = cls._hints self.assertTrue(cls in hints.returns) self.assertTrue(cls in hints.exact) self.assertTrue(JDouble in hints.implicit) self.assertTrue(JByte in hints.explicit) self.assertTrue(JChar in hints.explicit) self.assertTrue(JShort in hints.explicit) self.assertTrue(JInt in hints.explicit) self.assertTrue(JLong in hints.explicit) self.assertTrue(JFloat in hints.explicit) self.assertTrue(JClass('java.lang.Double') in hints.explicit) self.assertTrue(proto.SupportsIndex in hints.explicit) self.assertTrue(proto.SupportsFloat in hints.explicit) self.assertTrue(int in hints.explicit) self.assertTrue(len(hints.none) == 0) def testObjectArray(self): cls = JClass('java.lang.Object[]') hints = cls._hints self.assertTrue(cls in hints.returns) self.assertTrue(cls in hints.exact) self.assertTrue(proto.Sequence in hints.implicit) self.assertTrue(len(hints.explicit) == 0) self.assertTrue(str in hints.none) def testBooleanArray(self): cls = JClass('boolean[]') hints = cls._hints self.assertTrue(cls in hints.returns) self.assertTrue(cls in hints.exact) self.assertTrue(proto.Sequence in hints.implicit) self.assertTrue(len(hints.explicit) == 0) self.assertTrue(str in hints.none) def testCharArray(self): cls = JClass('char[]') hints = cls._hints self.assertTrue(cls in hints.returns) self.assertTrue(cls in hints.exact) self.assertTrue(str in hints.implicit) self.assertTrue(proto.Sequence in hints.implicit) self.assertTrue(len(hints.explicit) == 0) self.assertTrue(len(hints.none) == 0) def testShortArray(self): cls = JClass('short[]') hints = cls._hints self.assertTrue(cls in hints.returns) self.assertTrue(cls in hints.exact) self.assertTrue(proto.Sequence in hints.implicit) self.assertTrue(len(hints.explicit) == 0) self.assertTrue(str in hints.none) def testIntArray(self): cls = JClass('int[]') hints = cls._hints self.assertTrue(cls in hints.returns) self.assertTrue(cls in hints.exact) self.assertTrue(proto.Sequence in hints.implicit) self.assertTrue(len(hints.explicit) == 0) self.assertTrue(str in hints.none) def testLongArray(self): cls = JClass('long[]') hints = cls._hints self.assertTrue(cls in hints.returns) self.assertTrue(cls in hints.exact) self.assertTrue(proto.Sequence in hints.implicit) self.assertTrue(len(hints.explicit) == 0) self.assertTrue(str in hints.none) def testFloatArray(self): cls = JClass('float[]') hints = cls._hints self.assertTrue(cls in hints.returns) self.assertTrue(cls in hints.exact) self.assertTrue(proto.Sequence in hints.implicit) self.assertTrue(len(hints.explicit) == 0) self.assertTrue(str in hints.none) def testDoubleArray(self): cls = JClass('double[]') hints = cls._hints self.assertTrue(cls in hints.returns) self.assertTrue(cls in hints.exact) self.assertTrue(proto.Sequence in hints.implicit) self.assertTrue(len(hints.explicit) == 0) self.assertTrue(str in hints.none) def testPath(self): cls = JClass('java.nio.file.Path') hints = cls._hints self.assertTrue(cls in hints.returns) self.assertTrue(cls in hints.exact) self.assertTrue(proto.SupportsPath in hints.implicit) self.assertTrue(len(hints.explicit) == 0) self.assertTrue(len(hints.none) == 0) def testFile(self): cls = JClass('java.io.File') hints = cls._hints self.assertTrue(cls in hints.returns) self.assertTrue(cls in hints.exact) self.assertTrue(proto.SupportsPath in hints.implicit) self.assertTrue(len(hints.explicit) == 0) self.assertTrue(len(hints.none) == 0) def testInstant(self): import datetime cls = JClass('java.time.Instant') hints = cls._hints self.assertTrue(cls in hints.returns) self.assertTrue(cls in hints.exact) self.assertTrue(datetime.datetime in hints.implicit) self.assertTrue(len(hints.explicit) == 0) self.assertTrue(len(hints.none) == 0) def testDate(self): cls = JClass("java.sql.Date") d = cls(120, 0, 5) d2 = d._py() d3 = JObject(d2, cls) self.assertEqual(d, d2) self.assertEqual(d, d3) def testTimestamp(self): cls = JClass("java.sql.Timestamp") d = cls(120, 0, 5, 9, 22, 51, 123456000) d2 = d._py() d3 = JObject(d2, cls) self.assertEqual(d, d2) self.assertEqual(d, d3) def testTime(self): cls = JClass("java.sql.Time") d = cls(11, 53, 1) d2 = d._py() d3 = JObject(d2, cls) self.assertEqual(d, d2) self.assertEqual(d, d3) def testBigDecimal(self): cls = JClass("java.math.BigDecimal") d = cls('1000234600000000000000') d2 = d._py() d3 = JObject(d2, cls) self.assertEqual(d, d2) self.assertEqual(d, d3) def testAddTypeBad(self): cls = JClass('java.lang.Object') with self.assertRaises(TypeError): cls._hints._addTypeConversion() with self.assertRaisesRegex(TypeError, "callable method is required"): cls._hints._addTypeConversion(object, object(), True) with self.assertRaisesRegex(TypeError, "type or protocol is required"): def foo(): pass cls._hints._addTypeConversion(object(), foo, True) def testExcludeBad(self): cls = JClass('java.lang.Object') with self.assertRaisesRegex(TypeError, "type or protocol is required, not 'object'"): cls._hints._excludeConversion(object()) with self.assertRaisesRegex(TypeError, "type or protocol is required, not 'object'"): cls._hints._excludeConversion((object(),)) jpype-1.3.0/test/jpypetest/test_imports.py000066400000000000000000000116501405671516700207750ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import jpype import sys import logging import time import common import subrun def haveJImports(): try: import jpype.imports return True except ImportError: return False def isJavaClass(tp): return isinstance(tp, jpype.JClass) def isJavaEnum(tp): return issubclass(tp, jpype.JClass('java.lang.Enum')) class ImportsTestCase(common.JPypeTestCase): def setUp(self): # logger = logging.getLogger(__name__) # logger.info("TEST:JImports") common.JPypeTestCase.setUp(self) @common.unittest.skipUnless(haveJImports(), "jpype.imports not available") def testImportPackage(self): import java.lang self.assertTrue(isJavaClass(java.lang.String)) @common.unittest.skipUnless(haveJImports(), "jpype.imports not available") def testImportClass(self): from java.lang import String self.assertTrue(isJavaClass(String)) @common.unittest.skipUnless(haveJImports(), "jpype.imports not available") def testImportClassAs(self): from java.lang import String as Str self.assertTrue(isJavaClass(Str)) @common.unittest.skipUnless(haveJImports(), "jpype.imports not available") def testImportClassMultiple(self): from java.lang import Number, Integer, Double self.assertTrue(isJavaClass(Number)) self.assertTrue(isJavaClass(Integer)) self.assertTrue(isJavaClass(Double)) @common.unittest.skipUnless(haveJImports(), "jpype.imports not available") def testImportStatic(self): from java.lang.ProcessBuilder import Redirect self.assertTrue(isJavaClass(Redirect)) @common.unittest.skipUnless(haveJImports(), "jpype.imports not available") def testImportInner(self): from java.lang import Character self.assertTrue(isJavaClass(Character.UnicodeScript)) @common.unittest.skipUnless(haveJImports(), "jpype.imports not available") def testImportInnerEnum(self): from java.lang import Character self.assertTrue(isJavaEnum(Character.UnicodeScript)) def testImportFail(self): with self.assertRaises(ImportError): from java.lang import NotThere def testAlias1(self): jpype.imports.registerDomain("jpypex", alias="jpype") from jpypex.common import Fixture self.assertEqual(Fixture, jpype.JClass("jpype.common.Fixture")) def testAlias2(self): jpype.imports.registerDomain("commonx", alias="jpype.common") from commonx import Fixture as Fixture2 self.assertEqual(Fixture2, jpype.JClass("jpype.common.Fixture")) def testAliasBad(self): jpype.imports.registerDomain("brokenx", alias="jpype.broken") with self.assertRaises(ImportError): from brokenx import Fixture as Fixture2 def testIsPackage(self): import java.lang self.assertIsInstance(java, jpype.JPackage) self.assertIsInstance(java.lang, jpype.JPackage) self.assertFalse(isinstance(java.lang.Class, jpype.JPackage)) self.assertTrue(issubclass(type(java.lang), jpype.JPackage)) def testMRJar(self): import org.jpype.mrjar as mrjar u = dir(mrjar) self.assertTrue("A" in u) self.assertTrue("B" in u) self.assertTrue("sub" in u) def testAddClassPath(self): import pathlib import org.jpype as ojp self.assertFalse("late" in dir(ojp)) with self.assertRaises(ImportError): import org.jpype.late as late jpype.addClassPath(pathlib.Path("test/jar/late/late.jar").absolute()) import org.jpype.late as late self.assertTrue("Test" in dir(late)) t = late.Test() self.assertTrue(t.field == 5) self.assertTrue(t.method() == "Yes") def testStar(self): import importstar def testMissing(self): import org self.assertTrue("missing" in dir(org.jpype)) @subrun.TestCase class ImportsBeforeCase(common.unittest.TestCase): def setUp(self): self.jvmpath = jpype.getDefaultJVMPath() def testPre(self): with self.assertRaises(ImportError): import java with self.assertRaises(ImportError): import java.lang jpype-1.3.0/test/jpypetest/test_inherit.py000066400000000000000000000126771405671516700207540ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import jpype from jpype.types import * from jpype import java, JInterface import common class InheritTestCase(common.JPypeTestCase): """ test for isinstance and issubclass """ def setUp(self): common.JPypeTestCase.setUp(self) def assertIsSubclass(self, a, b): if not issubclass(a, b): raise AssertionError("'%s' is not a subclass of '%s'" % (a, b)) def assertNotIsSubclass(self, a, b): if issubclass(a, b): raise AssertionError("'%s' is a subclass of '%s'" % (a, b)) def testPrimitivesAsObjects(self): self.assertNotIsInstance(JBoolean(1), JObject) self.assertNotIsInstance(JByte(1), JObject) self.assertNotIsInstance(JChar(1), JObject) self.assertNotIsInstance(JShort(1), JObject) self.assertNotIsInstance(JInt(1), JObject) self.assertNotIsInstance(JLong(1), JObject) self.assertNotIsInstance(JFloat(1), JObject) self.assertNotIsInstance(JDouble(1), JObject) self.assertNotIsSubclass(JBoolean, JObject) self.assertNotIsSubclass(JByte, JObject) self.assertNotIsSubclass(JChar, JObject) self.assertNotIsSubclass(JShort, JObject) self.assertNotIsSubclass(JInt, JObject) self.assertNotIsSubclass(JLong, JObject) self.assertNotIsSubclass(JFloat, JObject) self.assertNotIsSubclass(JDouble, JObject) def testPrimitivesAsInterfaces(self): self.assertNotIsInstance(JBoolean, JInterface) self.assertNotIsInstance(JByte, JInterface) self.assertNotIsInstance(JChar, JInterface) self.assertNotIsInstance(JShort, JInterface) self.assertNotIsInstance(JInt, JInterface) self.assertNotIsInstance(JLong, JInterface) self.assertNotIsInstance(JFloat, JInterface) self.assertNotIsInstance(JDouble, JInterface) def testPrimitivesAsClasses(self): self.assertIsInstance(JBoolean, JClass) self.assertIsInstance(JByte, JClass) self.assertIsInstance(JChar, JClass) self.assertIsInstance(JShort, JClass) self.assertIsInstance(JInt, JClass) self.assertIsInstance(JLong, JClass) self.assertIsInstance(JFloat, JClass) self.assertIsInstance(JDouble, JClass) def testString(self): self.assertIsSubclass(JString, JObject) self.assertIsSubclass(java.lang.String, JObject) self.assertIsSubclass(JString, JString) self.assertIsSubclass(java.lang.String, JString) self.assertIsInstance(JString("f"), JObject) self.assertIsInstance(java.lang.String("f"), JObject) self.assertIsInstance(JString("f"), JString) self.assertIsInstance(java.lang.String("f"), JString) self.assertNotIsInstance(JString, JInterface) self.assertNotIsInstance(java.lang.String, JInterface) self.assertIsSubclass(JString, java.lang.String) def testObject(self): self.assertIsInstance(JObject, JClass) self.assertIsInstance(java.lang.Object, JClass) self.assertNotIsSubclass(JObject, JInterface) self.assertNotIsSubclass(java.lang.Object, JInterface) self.assertIsSubclass(JObject, JObject) self.assertIsSubclass(JObject, java.lang.Object) self.assertNotIsSubclass(JObject, JException) self.assertNotIsInstance(JObject(), JInterface) self.assertNotIsInstance(java.lang.Object(), JInterface) self.assertIsInstance(JObject(), JObject) self.assertIsInstance(JObject(), java.lang.Object) def testException(self): # JException is a bit of screw ball as it must be # a subclass of Exception so we can catch it, but at the same # time it is also a meta class in the original API. self.assertIsInstance(JException, JClass) self.assertIsInstance(java.lang.Throwable, JClass) self.assertNotIsSubclass(JException, JInterface) self.assertNotIsSubclass(java.lang.Throwable, JInterface) self.assertIsSubclass(JException, Exception) self.assertIsSubclass(JException, JException) self.assertNotIsInstance(java.lang.Throwable("f"), JInterface) th = java.lang.Throwable("foo") self.assertIsInstance(th, JObject) self.assertIsInstance(th, java.lang.Object) self.assertIsInstance(th, java.lang.Throwable) self.assertIsInstance(th, JException) self.assertIsInstance(th, Exception) with self.assertRaises(Exception): raise th with self.assertRaises(JException): raise th def testInterface(self): # JInterface is a meta but was a base class at some point self.assertIsInstance(java.io.Serializable, JInterface) self.assertIsSubclass(java.io.Serializable, JInterface) jpype-1.3.0/test/jpypetest/test_javacoverage.py000066400000000000000000000136541405671516700217430ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import _jpype import jpype import _jpype from jpype.types import * from jpype import java, JImplements, JOverride import common class JavaCoverageTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) self.fixture = JClass('jpype.common.Fixture')() JPypeContext = JClass('org.jpype.JPypeContext') self.inst = JPypeContext.getInstance() def testTypeFactory(self): self.assertNotEqual(self.inst.getTypeFactory(), None) def testContext(self): self.assertEqual(self.inst.collectRectangular(None), None) self.assertEqual(self.inst.collectRectangular(JString('hello')), None) self.assertEqual(self.inst.collectRectangular( JArray(JObject, 2)([JArray(JObject)(0)])), None) self.assertEqual(self.inst.collectRectangular( JArray(JObject)([None, None])), None) self.assertEqual(self.inst.getExcValue(None), 0) def testReference(self): JPypeReference = JClass('org.jpype.ref.JPypeReference') u = JPypeReference(None, None, 0, 0) u2 = JPypeReference(None, None, 1, 0) self.assertTrue(u.equals(u)) self.assertFalse(u.equals(u2)) self.assertFalse(u.equals(JString("a"))) def testModifiers(self): cls = JClass('org.jpype.manager.ModifierCode') self.assertEqual(cls.get(cls.decode(1171)), 1171) def testTypeFactory(self): TypeFactory = JClass("org.jpype.manager.TypeFactory") TypeManager = JClass("org.jpype.manager.TypeManager") @JImplements(TypeFactory) class TF(object): def __init__(self): self.id = 0 self.entities = {} def define(self, name): self.id += 1 self.entities[self.id] = name return self.id @JOverride def newWrapper(self, context, cls): pass @JOverride def defineArrayClass(self, context, cls, name, superClass, componentPtr, modifiers): return self.define(name) @JOverride def defineObjectClass(self, context, cls, name, superClass, interfaces, modifiers): return self.define(name) @JOverride def definePrimitive(self, context, name, cls, boxedPtr, modifiers): return self.define(name) @JOverride def assignMembers(self, context, cls, ctorMethod, methodList, fieldList): return @JOverride def defineField(self, context, cls, name, field, fieldType, modifiers): return self.define(name) @JOverride def defineMethod(self, context, cls, name, method, overloadList, modifiers): return self.define(name) @JOverride def populateMethod(self, context, method, returnType, argumentTypes): return @JOverride def defineMethodDispatch(self, context, cls, name, overloadList, modifiers): return self.define(name) @JOverride def destroy(self, context, resources, sz): for i in range(sz): del self.entities[resources[i]] manager = TypeManager() factory = TF() manager = TypeManager(62621463, factory) manager.init() # Can only be initialized once with self.assertRaises(JException): manager.init() self.assertEqual( factory.entities[manager.findClassByName('boolean')], 'boolean') self.assertEqual( factory.entities[manager.findClassByName('byte')], 'byte') self.assertEqual( factory.entities[manager.findClassByName('char')], 'char') self.assertEqual( factory.entities[manager.findClassByName('short')], 'short') self.assertEqual( factory.entities[manager.findClassByName('int')], 'int') self.assertEqual( factory.entities[manager.findClassByName('long')], 'long') self.assertEqual( factory.entities[manager.findClassByName('float')], 'float') self.assertEqual( factory.entities[manager.findClassByName('double')], 'double') self.assertEqual( factory.entities[manager.findClass(JBoolean)], "boolean") self.assertEqual(factory.entities[manager.findClass(JChar)], "char") self.assertEqual(factory.entities[manager.findClass(JByte)], "byte") self.assertEqual(factory.entities[manager.findClass(JShort)], "short") self.assertEqual(factory.entities[manager.findClass(JInt)], "int") self.assertEqual(factory.entities[manager.findClass(JLong)], "long") self.assertEqual(factory.entities[manager.findClass(JFloat)], "float") self.assertEqual( factory.entities[manager.findClass(JDouble)], "double") self.assertEqual(manager.populateMethod(0, None), None) sb = JClass("java.lang.StringBuilder") with self.assertRaises(JException): manager.populateMembers(sb) manager.shutdown() # See if we leaked any entities self.assertEqual(len(factory.entities), 0) jpype-1.3.0/test/jpypetest/test_javadoc.py000066400000000000000000000032511405671516700207050ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import jpype from jpype.types import * from jpype import java import common class HtmlTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) def testEntities(self): html = JClass("org.jpype.html.Html") for k, v in html.ENTITIES.items(): u = html.decode("&" + str(k) + ";") self.assertIsInstance(u, JString) self.assertEqual(len(u), 1) self.assertEqual(ord(u[0][0]), v) def testClass(self): JC = jpype.JClass("jpype.doc.Test") jd = JC.__doc__ self.assertIsInstance(jd, str) self.assertRegex(jd, "random stuff") def testMethod(self): JC = jpype.JClass("jpype.doc.Test") jd = JC.methodOne.__doc__ self.assertIsInstance(jd, str) # Disabling this test for now. Something fails in Linux but I can't replicate it. #self.assertRegex(jd, "something special") jpype-1.3.0/test/jpypetest/test_jboolean.py000066400000000000000000000126251405671516700210740ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import _jpype import jpype from jpype.types import * import sys import logging import time import common try: import numpy as np except ImportError: pass class JBooleanTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) self.Test = jpype.JClass("jpype.common.Fixture")() @common.requireInstrumentation def testJPBoolean_str(self): jb = JBoolean(True) _jpype.fault("PyJPBoolean_str") with self.assertRaisesRegex(SystemError, "fault"): str(jb) _jpype.fault("PyJPModule_getContext") str(jb) @common.requireInstrumentation def testJPBooleanType(self): ja = JArray(JBoolean)(5) # lgtm [py/similar-function] _jpype.fault("JPBooleanType::setArrayRange") with self.assertRaisesRegex(SystemError, "fault"): ja[1:3] = [0, 0] with self.assertRaises(TypeError): ja[1] = object() jf = JClass("jpype.common.Fixture") with self.assertRaises(TypeError): jf.static_bool_field = object() with self.assertRaises(TypeError): jf().bool_field = object() @common.requireInstrumentation def testJBooleanGetJavaConversion(self): _jpype.fault("JPBooleanType::findJavaConversion") with self.assertRaisesRegex(SystemError, "fault"): JBoolean._canConvertToJava(object()) def testBooleanFromInt(self): self.assertEqual(self.Test.callBoolean(int(123)), True) self.assertEqual(self.Test.callBoolean(int(0)), False) @common.requireNumpy def testBooleanFromNPInt(self): import numpy as np self.assertEqual(self.Test.callBoolean(np.int(123)), True) @common.requireNumpy def testBooleanFromNPInt8(self): import numpy as np self.assertEqual(self.Test.callBoolean(np.int8(123)), True) self.assertEqual(self.Test.callBoolean(np.uint8(123)), True) @common.requireNumpy def testBooleanFromNPInt16(self): import numpy as np self.assertEqual(self.Test.callBoolean(np.int16(123)), True) self.assertEqual(self.Test.callBoolean(np.uint16(123)), True) @common.requireNumpy def testBooleanFromNPInt32(self): import numpy as np self.assertEqual(self.Test.callBoolean(np.int32(123)), True) self.assertEqual(self.Test.callBoolean(np.uint32(123)), True) @common.requireNumpy def testBooleanFromNPInt64(self): import numpy as np self.assertEqual(self.Test.callBoolean(np.int64(123)), True) self.assertEqual(self.Test.callBoolean(np.uint64(123)), True) def testBooleanFromFloat(self): with self.assertRaises(TypeError): self.Test.callBoolean(float(2)) @common.requireNumpy def testBooleanFromNPFloat(self): import numpy as np with self.assertRaises(TypeError): self.Test.callBoolean(np.float(2)) @common.requireNumpy def testBooleanFromNPFloat32(self): import numpy as np with self.assertRaises(TypeError): self.Test.callBoolean(np.float32(2)) @common.requireNumpy def testBooleanFromNPFloat64(self): import numpy as np with self.assertRaises(TypeError): self.Test.callBoolean(np.float64(2)) def testBooleanFromNone(self): with self.assertRaises(TypeError): self.Test.callBoolean(None) def testJArrayConversionBool(self): expected = [True, False, False, True] jarr = jpype.JArray(jpype.JBoolean)(expected) self.assertEqual(expected, list(jarr[:])) @common.requireNumpy def testSetFromNPBoolArray(self): import numpy as np n = 100 a = np.random.randint(0, 1, size=n, dtype=np.bool) jarr = jpype.JArray(jpype.JBoolean)(n) jarr[:] = a self.assertCountEqual(a, jarr) @common.requireNumpy def testArrayBufferDims(self): ja = JArray(JBoolean)(5) a = np.zeros((5, 2)) with self.assertRaisesRegex(TypeError, "incorrect"): ja[:] = a def testArrayBadItem(self): class q(object): def __bool__(self): raise SystemError("nope") ja = JArray(JBoolean)(5) a = [1, 2, q(), 3, 4] with self.assertRaisesRegex(SystemError, "nope"): ja[:] = a def testArrayBadDims(self): class q(bytes): # Lie about our length def __len__(self): return 5 a = q([1, 2, 3]) ja = JArray(JBoolean)(5) with self.assertRaisesRegex(ValueError, "Slice"): ja[:] = [1, 2, 3] with self.assertRaisesRegex(ValueError, "mismatch"): ja[:] = a jpype-1.3.0/test/jpypetest/test_jbyte.py000066400000000000000000000166421405671516700204230ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import _jpype import jpype from jpype.types import * from jpype import java import sys import logging import time import common try: import numpy as np except ImportError: pass class JByteTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) self.fixture = jpype.JClass("jpype.common.Fixture")() @common.requireInstrumentation def testConversionFault(self): _jpype.fault("JPByteType::findJavaConversion") with self.assertRaisesRegex(SystemError, "fault"): JByte._canConvertToJava(object()) @common.requireInstrumentation def testArrayFaults(self): ja = JArray(JByte)(5) _jpype.fault("JPByteType::setArrayRange") with self.assertRaisesRegex(SystemError, "fault"): ja[1:3] = [0, 0] _jpype.fault("JPJavaFrame::NewByteArray") with self.assertRaisesRegex(SystemError, "fault"): JArray(JByte)(1) _jpype.fault("JPJavaFrame::SetByteArrayRegion") with self.assertRaisesRegex(SystemError, "fault"): ja[0] = 0 _jpype.fault("JPJavaFrame::GetByteArrayRegion") with self.assertRaisesRegex(SystemError, "fault"): print(ja[0]) _jpype.fault("JPJavaFrame::GetByteArrayElements") with self.assertRaises(BufferError): memoryview(ja[0:3]) _jpype.fault("JPJavaFrame::ReleaseByteArrayElements") with self.assertRaisesRegex(SystemError, "fault"): ja[0:3] = bytes([1, 2, 3]) _jpype.fault("JPJavaFrame::ReleaseByteArrayElements") with self.assertRaisesRegex(SystemError, "fault"): jpype.JObject(ja[::2], jpype.JObject) _jpype.fault("JPJavaFrame::ReleaseByteArrayElements") def f(): # Special case no fault is allowed memoryview(ja[0:3]) f() def testByteFromInt(self): self.assertEqual(self.fixture.callByte(int(123)), 123) @common.requireNumpy def testByteFromNPInt(self): import numpy as np self.assertEqual(self.fixture.callByte(np.int(123)), 123) @common.requireNumpy def testByteFromNPInt8(self): import numpy as np self.assertEqual(self.fixture.callByte(np.int8(123)), 123) self.assertEqual(self.fixture.callByte(np.uint8(123)), 123) @common.requireNumpy def testByteFromNPInt16(self): import numpy as np self.assertEqual(self.fixture.callByte(np.int16(123)), 123) self.assertEqual(self.fixture.callByte(np.uint16(123)), 123) @common.requireNumpy def testByteFromNPInt32(self): import numpy as np self.assertEqual(self.fixture.callByte(np.int32(123)), 123) self.assertEqual(self.fixture.callByte(np.uint32(123)), 123) @common.requireNumpy def testByteFromNPInt64(self): import numpy as np self.assertEqual(self.fixture.callByte(np.int64(123)), 123) self.assertEqual(self.fixture.callByte(np.uint64(123)), 123) def testByteFromFloat(self): with self.assertRaises(TypeError): self.fixture.callByte(float(2)) @common.requireNumpy def testByteFromNPFloat(self): import numpy as np with self.assertRaises(TypeError): self.fixture.callByte(np.float(2)) @common.requireNumpy def testByteFromNPFloat32(self): import numpy as np with self.assertRaises(TypeError): self.fixture.callByte(np.float32(2)) @common.requireNumpy def testByteFromNPFloat64(self): import numpy as np with self.assertRaises(TypeError): self.fixture.callByte(np.float64(2)) def testByteRange(self): with self.assertRaises(OverflowError): self.fixture.callByte(int(1e10)) with self.assertRaises(OverflowError): self.fixture.callByte(int(-1e10)) def testExplicitRange(self): # These will not overflow as they are explicit casts self.assertEqual(JByte(2**8), 0) self.assertEqual(JByte(-2**8), 0) def testByteFromNone(self): with self.assertRaises(TypeError): self.fixture.callByte(None) def testByteArrayAsString(self): t = JClass("jpype.array.TestArray")() v = t.getByteArray() self.assertEqual(str(v), 'avcd') def testByteArrayIntoVector(self): ba = jpype.JArray(jpype.JByte)(b'123') v = jpype.java.util.Vector(1) v.add(ba) self.assertEqual(len(v), 1) self.assertNotEqual(v[0], None) def testByteArraySimple(self): a = JArray(JByte)(2) a[1] = 2 self.assertEqual(a[1], 2) def testJArrayConversionByte(self): expected = (0, 1, 2, 3) ByteBuffer = jpype.java.nio.ByteBuffer bb = ByteBuffer.allocate(4) buf = bb.array() for i in range(len(expected)): buf[i] = expected[i] for i in range(len(expected)): self.assertEqual(expected[i], buf[i]) def testFromObject(self): ja = JArray(JByte)(5) with self.assertRaises(TypeError): ja[1] = object() jf = JClass("jpype.common.Fixture") with self.assertRaises(TypeError): jf.static_byte_field = object() with self.assertRaises(TypeError): jf().byte_field = object() def testArrayHash(self): ja = JArray(JByte)([1, 2, 3]) self.assertIsInstance(hash(ja), int) @common.requireNumpy def testArrayBufferDims(self): ja = JArray(JByte)(5) a = np.zeros((5, 2)) with self.assertRaisesRegex(TypeError, "incorrect"): ja[:] = a def testArrayBadItem(self): class q(object): def __int__(self): raise SystemError("nope") def __index__(self): raise SystemError("nope") ja = JArray(JByte)(5) a = [1, -1, q(), 3, 4] with self.assertRaisesRegex(SystemError, "nope"): ja[:] = a def testArrayBadDims(self): class q(bytes): # Lie about our length def __len__(self): return 5 a = q([1, 2, 3]) ja = JArray(JByte)(5) with self.assertRaisesRegex(ValueError, "Slice"): ja[:] = [1, 2, 3] with self.assertRaisesRegex(ValueError, "mismatch"): ja[:] = a def testArraySetRange(self): ja = JArray(JByte)(3) ja[0:1] = [123] self.assertEqual(ja[0], 123) ja[0:1] = [-1] self.assertEqual(ja[0], -1) with self.assertRaises(TypeError): ja[0:1] = [1.000] with self.assertRaises(TypeError): ja[0:1] = [java.lang.Double(321)] with self.assertRaises(TypeError): ja[0:1] = [object()] jpype-1.3.0/test/jpypetest/test_jchar.py000066400000000000000000000346261405671516700203770ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import _jpype import jpype import common from jpype.types import * class JChar2TestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) def testCharRange(self): self.assertEqual(ord(str(jpype.JChar(65))), 65) self.assertEqual(ord(str(jpype.JChar(512))), 512) def testCharFromStr(self): self.assertEqual(ord(jpype.JChar(chr(65))), 65) self.assertEqual(ord(jpype.JChar(chr(128))), 128) self.assertEqual(ord(jpype.JChar(chr(255))), 255) self.assertEqual(ord(jpype.JChar(chr(10255))), 10255) def testCharCastFloat(self): self.assertEqual(ord(jpype.JChar(65.0)), 65) @common.requireInstrumentation def testJPChar_new(self): _jpype.fault("PyJPChar_new") with self.assertRaisesRegex(SystemError, "fault"): JChar("a") _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): JChar("a") JChar("a") @common.requireInstrumentation def testJPChar_str(self): jc = JChar("a") _jpype.fault("PyJPChar_str") with self.assertRaisesRegex(SystemError, "fault"): str(jc) @common.requireInstrumentation def testJCharGetJavaConversion(self): _jpype.fault("JPCharType::findJavaConversion") with self.assertRaisesRegex(SystemError, "fault"): JChar._canConvertToJava(object()) @common.requireInstrumentation def testJPJavaFrameCharArray(self): ja = JArray(JChar)(5) _jpype.fault("JPJavaFrame::NewCharArray") with self.assertRaisesRegex(SystemError, "fault"): JArray(JChar)(1) _jpype.fault("JPJavaFrame::SetCharArrayRegion") with self.assertRaisesRegex(SystemError, "fault"): ja[0] = 0 _jpype.fault("JPJavaFrame::GetCharArrayRegion") with self.assertRaisesRegex(SystemError, "fault"): print(ja[0]) _jpype.fault("JPJavaFrame::GetCharArrayElements") # Special case, only BufferError is allowed from getBuffer with self.assertRaises(BufferError): memoryview(ja[0:3]) _jpype.fault("JPJavaFrame::ReleaseCharArrayElements") with self.assertRaisesRegex(SystemError, "fault"): ja[0:3] = bytes([1, 2, 3]) # Not sure why this one changed. _jpype.fault("JPJavaFrame::ReleaseCharArrayElements") with self.assertRaisesRegex(SystemError, "fault"): jpype.JObject(ja[::2], jpype.JObject) _jpype.fault("JPJavaFrame::ReleaseCharArrayElements") def f(): # Special case no fault is allowed memoryview(ja[0:3]) f() ja = JArray(JChar)(5) # lgtm [py/similar-function] _jpype.fault("JPCharType::setArrayRange") with self.assertRaisesRegex(SystemError, "fault"): ja[1:3] = [0, 0] def testFromObject(self): ja = JArray(JChar)(5) with self.assertRaises(TypeError): ja[1] = object() jf = JClass("jpype.common.Fixture") with self.assertRaises(TypeError): jf.static_char_field = object() with self.assertRaises(TypeError): jf().char_field = object() def testCharArrayAsString(self): t = JClass("jpype.array.TestArray")() v = t.getCharArray() self.assertEqual(str(v), 'avcd') def testArrayConversionChar(self): t = JClass("jpype.array.TestArray")() v = t.getCharArray() self.assertEqual(str(v[:]), 'avcd') def testArrayEqualsChar(self): contents = "abc" array = jpype.JArray(jpype.JChar)(contents) array2 = jpype.JArray(jpype.JChar)(contents) self.assertEqual(array, array) self.assertNotEqual(array, array2) self.assertEqual(array, "abc") def testArrayHash(self): ja = JArray(JByte)([1, 2, 3]) self.assertIsInstance(hash(ja), int) def testNone(self): self.assertEqual(JChar._canConvertToJava(None), "none") class JCharTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) self.nc = JChar('B') def testStr(self): self.assertEqual(type(str(self.nc)), str) self.assertEqual(str(self.nc), 'B') def testRepr(self): self.assertEqual(type(repr(self.nc)), str) self.assertEqual(repr(self.nc), "'B'") def testAbs(self): self.assertEqual(abs(self.nc), self.nc) def testOrd(self): self.assertEqual(ord(self.nc), 66) def testInt(self): self.assertEqual(int(self.nc), 66) def testFloat(self): self.assertEqual(float(self.nc), 66.0) def testLen(self): self.assertEqual(len(self.nc), 1) def testHash(self): self.assertEqual(hash(self.nc), hash('B')) def testAdd(self): self.assertEqual(self.nc + 1, 67) self.assertIsInstance(self.nc + 1, int) self.assertEqual(self.nc + 1.1, 67.1) self.assertIsInstance(self.nc + 1.1, float) def testSub(self): self.assertEqual(self.nc - 1, 65) self.assertIsInstance(self.nc - 1, int) self.assertEqual(self.nc - 1.1, 64.9) self.assertIsInstance(self.nc - 1.1, float) def testMult(self): self.assertEqual(self.nc * 2, 132) self.assertIsInstance(self.nc * 2, int) self.assertEqual(self.nc * 0.25, 16.5) self.assertIsInstance(self.nc * 2.0, float) def testRshift(self): self.assertEqual(self.nc >> 1, 33) self.assertIsInstance(self.nc >> 2, int) def testLshift(self): self.assertEqual(self.nc << 1, 132) self.assertIsInstance(self.nc << 2, int) def testAnd(self): self.assertEqual(self.nc & 244, 66 & 244) self.assertIsInstance(self.nc & 2, int) def testOr(self): self.assertEqual(self.nc | 40, 66 | 40) self.assertIsInstance(self.nc | 2, int) def testXor(self): self.assertEqual(self.nc ^ 1, 66 ^ 1) self.assertIsInstance(self.nc ^ 1, int) def testPass(self): fixture = jpype.JClass('jpype.common.Fixture')() self.assertEqual(type(fixture.callChar(self.nc)), JChar) self.assertEqual(type(fixture.callObject(self.nc)), jpype.java.lang.Character) def check(self, u, v0, v1, v2): self.assertEqual(v1, u) self.assertEqual(u, v1) self.assertNotEqual(v0, u) self.assertNotEqual(u, v0) self.assertNotEqual(v2, u) self.assertNotEqual(u, v2) self.assertTrue(u > v0) self.assertFalse(u > v2) self.assertTrue(u < v2) self.assertFalse(u < v0) self.assertTrue(v0 < u) self.assertFalse(v2 < u) self.assertTrue(v2 > u) self.assertFalse(v0 > u) self.assertTrue(u >= v1) self.assertFalse(u >= v2) self.assertTrue(v1 <= u) self.assertFalse(v2 <= u) def testCompareInt(self): self.check(self.nc, 65, 66, 67) def testCompareFloat(self): self.check(self.nc, 65.0, 66.0, 67.0) def testCompareJInt(self): self.check(self.nc, JInt(65), JInt(66), JInt(67)) def testCompareJFloat(self): self.check(self.nc, JFloat(65.0), JFloat(66.0), JFloat(67.0)) class JCharBoxedTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) self.nc = jpype.java.lang.Character('B') def testStr(self): self.assertEqual(type(str(self.nc)), str) self.assertEqual(str(self.nc), 'B') def testRepr(self): self.assertEqual(type(repr(self.nc)), str) self.assertEqual(repr(self.nc), "'B'") def testOrd(self): self.assertEqual(ord(self.nc), 66) def testInt(self): self.assertEqual(int(self.nc), 66) def testFloat(self): self.assertEqual(float(self.nc), 66.0) def testLen(self): self.assertEqual(len(self.nc), 1) def testHash(self): self.assertEqual(hash(self.nc), hash('B')) def testAdd(self): self.assertEqual(self.nc + 1, 67) self.assertIsInstance(self.nc + 1, int) self.assertEqual(self.nc + 1.1, 67.1) self.assertIsInstance(self.nc + 1.1, float) def testSub(self): self.assertEqual(self.nc - 1, 65) self.assertIsInstance(self.nc - 1, int) self.assertEqual(self.nc - 1.1, 64.9) self.assertIsInstance(self.nc - 1.1, float) def testMult(self): self.assertEqual(self.nc * 2, 132) self.assertIsInstance(self.nc * 2, int) self.assertEqual(self.nc * 0.25, 16.5) self.assertIsInstance(self.nc * 2.0, float) def testRshift(self): self.assertEqual(self.nc >> 1, 33) self.assertIsInstance(self.nc >> 2, int) def testLshift(self): self.assertEqual(self.nc << 1, 132) self.assertIsInstance(self.nc << 2, int) def testAnd(self): self.assertEqual(self.nc & 244, 66 & 244) self.assertIsInstance(self.nc & 2, int) def testOr(self): self.assertEqual(self.nc | 40, 66 | 40) self.assertIsInstance(self.nc | 2, int) def testXor(self): self.assertEqual(self.nc ^ 1, 66 ^ 1) self.assertIsInstance(self.nc ^ 1, int) def testFloorDiv(self): self.assertEqual(self.nc // 3, 66 // 3) self.assertEqual(3 // self.nc, 3 // 66) def testDivMod(self): self.assertEqual(divmod(self.nc, 3), divmod(66, 3)) self.assertEqual(divmod(3, self.nc), divmod(3, 66)) def testInv(self): self.assertEqual(~self.nc, ~66) def testPos(self): self.assertEqual(+self.nc, +66) def testNeg(self): self.assertEqual(-self.nc, -66) def testBool(self): self.assertTrue(bool(self.nc)) self.assertFalse(bool(JChar(0))) def testPass(self): fixture = jpype.JClass('jpype.common.Fixture')() self.assertEqual(type(fixture.callObject(self.nc)), type(self.nc)) def check(self, u, v0, v1, v2): self.assertEqual(v1, u) self.assertEqual(u, v1) self.assertNotEqual(v0, u) self.assertNotEqual(u, v0) self.assertNotEqual(v2, u) self.assertNotEqual(u, v2) self.assertTrue(u > v0) self.assertFalse(u > v2) self.assertTrue(u < v2) self.assertFalse(u < v0) self.assertTrue(v0 < u) self.assertFalse(v2 < u) self.assertTrue(v2 > u) self.assertFalse(v0 > u) self.assertTrue(u >= v1) self.assertFalse(u >= v2) self.assertTrue(v1 <= u) self.assertFalse(v2 <= u) def testCompareInt(self): self.check(self.nc, 65, 66, 67) def testCompareFloat(self): self.check(self.nc, 65.0, 66.0, 67.0) def testCompareJInt(self): self.check(self.nc, JInt(65), JInt(66), JInt(67)) def testCompareJFloat(self): self.check(self.nc, JFloat(65.0), JFloat(66.0), JFloat(67.0)) class JCharBoxedNullTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) self.nc = jpype.JObject(None, jpype.java.lang.Character) def testStr(self): self.assertEqual(type(str(self.nc)), str) self.assertEqual(str(self.nc), 'None') def testRepr(self): self.assertEqual(type(repr(self.nc)), str) self.assertEqual(repr(self.nc), 'None') def testInt(self): with self.assertRaises(TypeError): int(self.nc) def testFloat(self): with self.assertRaises(TypeError): float(self.nc) def testLen(self): with self.assertRaises(TypeError): len(self.nc) def testHash(self): self.assertEqual(hash(self.nc), hash(None)) def testAdd(self): with self.assertRaises(TypeError): self.nc + 1 with self.assertRaises(TypeError): 1 + self.nc def testSub(self): with self.assertRaises(TypeError): self.nc - 1 with self.assertRaises(TypeError): 1 - self.nc def testMult(self): with self.assertRaises(TypeError): self.nc * 1 with self.assertRaises(TypeError): 1 * self.nc def testRshift(self): with self.assertRaises(TypeError): self.nc >> 1 with self.assertRaises(TypeError): 1 >> self.nc def testLshift(self): with self.assertRaises(TypeError): self.nc << 1 with self.assertRaises(TypeError): 1 << self.nc def testAnd(self): with self.assertRaises(TypeError): self.nc & 1 with self.assertRaises(TypeError): 1 & self.nc def testOr(self): with self.assertRaises(TypeError): self.nc | 1 with self.assertRaises(TypeError): 1 | self.nc def testXor(self): with self.assertRaises(TypeError): self.nc ^ 1 with self.assertRaises(TypeError): 1 ^ self.nc def testFloorDiv(self): with self.assertRaises(TypeError): self.nc // 1 with self.assertRaises(TypeError): 1 // self.nc def testDivMod(self): with self.assertRaises(TypeError): divmod(self.nc, 1) with self.assertRaises(TypeError): divmod(1, self.nc) def testInv(self): with self.assertRaises(TypeError): ~self.nc def testPos(self): with self.assertRaises(TypeError): +self.nc def testNeg(self): with self.assertRaises(TypeError): -self.nc def testBool(self): self.assertFalse(bool(self.nc)) def testEq(self): self.assertTrue(self.nc == self.nc) self.assertFalse(self.nc != self.nc) def testPass(self): fixture = jpype.JClass('jpype.common.Fixture')() self.assertEqual(fixture.callObject(self.nc), None) jpype-1.3.0/test/jpypetest/test_jclass.py000066400000000000000000000236161405671516700205640ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import _jpype import jpype from jpype.types import * import common class JClassTestCase(common.JPypeTestCase): """ Test for methods of JClass Should test: - ``__getattribute__`` against methods, fields, python methods, and python properties - ``__setattr__`` against fields, final fields, python private fields - ``class_`` property - ``mro`` """ def setUp(self): common.JPypeTestCase.setUp(self) def testGetAttrPyMethod(self): cls = JClass('java.util.Iterator') obj = JClass('java.util.ArrayList')() obj.add(123) # Static python methods should be the same when accessed as classes or objects self.assertEqual(obj.iterator().next(), cls.next(obj.iterator())) def testGetAttrStaticMethod(self): cls = JClass('java.lang.Long') obj = cls(10) # Static java methods should be the same when accessed as classes or objects self.assertEqual(cls.bitCount(123), obj.bitCount(123)) def testGetAttrStaticField(self): cls = JClass('java.lang.String') obj = cls("foo") # Static fields should be the same when accessed as classes or objects self.assertEqual(cls.CASE_INSENSITIVE_ORDER, obj.CASE_INSENSITIVE_ORDER) def testSetAttrPythonField(self): cls = JClass('java.lang.String') # Setting a private field on a Java class is allowed cls._allowed = 1 with self.assertRaises(AttributeError): # Setting a public field on a Java class is forbidden cls.forbidden = 1 def testSetAttrFinal(self): cls = JClass('java.lang.Long') with self.assertRaises(AttributeError): # Setting a final field is forbidden cls.SIZE = 1 def testClass(self): cls = JClass('java.lang.Long') clsType = JClass('java.lang.Class') # Get class must return a java.lang.Class instance belonging to the class self.assertIsInstance(cls.class_, clsType) self.assertEqual(cls.class_.getSimpleName(), "Long") def testGetAttrProperty(self): cls = JClass('java.lang.RuntimeException') with self.assertRaises(AttributeError): value = cls.args def testSetAttrProperty(self): cls = JClass('java.lang.RuntimeException') with self.assertRaises(AttributeError): cls.args = 1 def testGetAttrStaticField(self): cls = JClass('jpype.common.Fixture') cls.static_object_field = "fred" self.assertEqual(cls.static_object_field, "fred") def testSetAttrStaticField(self): cls = JClass('jpype.common.Fixture') cls.static_object_field = "fred" def testGetAttrField(self): cls = JClass('jpype.common.Fixture') with self.assertRaises(AttributeError): v = cls.object_field def testSetAttrField(self): cls = JClass('jpype.common.Fixture') with self.assertRaises(AttributeError): cls.object_field = "fred" def testGetAttrPrivateField(self): cls = JClass('jpype.common.Fixture') with self.assertRaises(AttributeError): v = cls.privateObjectField def testSetAttrPrivateField(self): cls = JClass('jpype.common.Fixture') with self.assertRaises(AttributeError): cls.private_object_field = "fred" def testGetAttrFinalField(self): cls = JClass('jpype.common.Fixture') with self.assertRaises(AttributeError): v = cls.final_object_field def testSetAttrFinalField(self): cls = JClass('jpype.common.Fixture') with self.assertRaises(AttributeError): cls.final_object_field = "fred" def testGetAttrStaticFinalField(self): cls = JClass('jpype.common.Fixture') self.assertEqual(cls.final_static_object_field, "final static object field") def testSetAttrStaticFinalField(self): cls = JClass('jpype.common.Fixture') with self.assertRaises(AttributeError): cls.final_static_object_field = "bar" def testStaticMethod(self): cls = JClass('jpype.common.Fixture') cls.callStaticObject(JObject()) def testPrivateStaticMethod(self): cls = JClass('jpype.common.Fixture') with self.assertRaises(AttributeError): cls.callPrivateStaticObject(JObject()) def testMethod(self): cls = JClass('jpype.common.Fixture') with self.assertRaises(TypeError): cls.callObject(JObject()) cls.callObject(cls(), JObject()) def testPrivateMethod(self): cls = JClass('jpype.common.Fixture') with self.assertRaises(AttributeError): cls.callPrivateObject(JObject()) def testProtectedMethod(self): cls = JClass('jpype.common.Fixture') with self.assertRaises(AttributeError): cls.callProtectedObject(JObject()) def testJClassFail(self): with self.assertRaises(TypeError): cls = JClass("asdw.gqyr.jhnw") def testGetClassFromClass(self): cls = JClass('java.lang.Class') self.assertIsInstance(cls.class_, cls) def testGetClassFromInterface(self): intr = JClass('java.io.Serializable') cls = JClass('java.lang.Class') self.assertIsInstance(intr.class_, cls) def testInterfaceCtor(self): intr = JClass('java.io.Serializable') with self.assertRaises(TypeError): intr() def testJClassWithLoader(self): cl = JClass('java.lang.Class').class_.getClassLoader() self.assertIsInstance( JClass('java.lang.StringBuilder', loader=cl), JClass) @common.requireInstrumentation def testJavaConversionFault(self): _jpype.fault("JPClass::findJavaConversion") with self.assertRaisesRegex(SystemError, "fault"): print(jpype.java.lang.Class._canConvertToJava(None)) def testJavaConversion(self): a = JString("a") self.assertEqual( jpype.java.lang.Class._canConvertToJava(object()), "none") self.assertEqual( jpype.java.lang.Class._canConvertToJava(a.getClass()), "exact") self.assertEqual( jpype.java.lang.Class._canConvertToJava(JString), "exact") def testInnerClass(self): # This tests for problems when the inner class implements the # outer interface which creates a race condition. Success is # not throwing an exception test = JClass("jpype.types.InnerTest")() test.test() def testLookupGeneric(self): self.assertEqual(JClass('java.util.ArrayList<>'), JClass("java.util.ArrayList")) def testLookupJNI(self): self.assertEqual(JClass('java/lang/Object'), JClass("java.lang.Object")) def testLookupArray(self): self.assertEqual(JClass('int[]'), JArray(JInt)) self.assertEqual(JClass('int[][]'), JArray(JInt, 2)) self.assertEqual(JClass('int[][][]'), JArray(JInt, 3)) self.assertEqual(JClass('java.lang.Object[][][]'), JArray(JObject, 3)) def testLookupArrayJNI(self): self.assertEqual(JClass('[I'), JArray(JInt)) self.assertEqual(JClass('[[J'), JArray(JLong, 2)) self.assertEqual(JClass('[Ljava.lang.Object;'), JArray(JObject)) self.assertEqual(JClass('[Ljava/lang/Object;'), JArray(JObject)) def testClosed(self): with self.assertRaises(TypeError): class Q(JBoolean): pass with self.assertRaises(TypeError): class Q(JChar): pass with self.assertRaises(TypeError): class Q(JByte): pass with self.assertRaises(TypeError): class Q(JShort): pass with self.assertRaises(TypeError): class Q(JInt): pass with self.assertRaises(TypeError): class Q(JLong): pass with self.assertRaises(TypeError): class Q(JFloat): pass with self.assertRaises(TypeError): class Q(JDouble): pass def testAsArray(self): jo = JClass('java.lang.Object') self.assertEqual(jo[:], JArray(jo)) self.assertEqual(jo[:][:], JArray(jo, 2)) self.assertIsInstance(jo[5], JArray(jo)) self.assertEqual(len(jo[5]), 5) self.assertIsInstance(jo[5, :], JArray(jo, 2)) self.assertEqual(len(jo[5, :]), 5) with self.assertRaises(TypeError): self.assertEqual(jo[:, 5], JArray(jo, 2)) with self.assertRaises(TypeError): jo['foo'] def testCastEqual(self): jo = JClass('java.lang.Object') with self.assertRaises(TypeError): jo @= 5 def testCanCast(self): String = JClass("java.lang.String") self.assertFalse(String._canCast(1)) self.assertTrue(String._canCast("foo")) def testUnsatisfied(self): # This is testing what happens if a class fails to load properly due to # failures. A partial loaded class can lead to crashes. with self.assertRaises(JClass("java.lang.NoClassDefFoundError")): JClass("org.jpype.unsatisfied.TestClass") jpype-1.3.0/test/jpypetest/test_jdouble.py000066400000000000000000000352351405671516700207310ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import sys import jpype import common import random import _jpype import jpype from jpype import java from jpype.types import * try: import numpy as np except ImportError: pass class JDoubleTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) self.value = 1.0 + 1.0 / 65536 self.cls = JClass("jpype.common.Fixture") self.fixture = self.cls() def compareDoubleEqual(self, x, y, msg=None): if x == y: return if x < 0: x = -x if y < 0: y = -y a = (x + y) / 2 b = (x - y) if b < 0: b = -b if b < a * 1e-14: return msg = self._formatMessage(msg, '%s == %s' % (safe_repr(first), safe_repr(second))) raise self.failureException(msg) @common.requireInstrumentation def testJPNumberFloat_int(self): jd = JDouble(1) _jpype.fault("PyJPNumberFloat_int") with self.assertRaisesRegex(SystemError, "fault"): int(jd) _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): int(jd) int(jd) @common.requireInstrumentation def testJPNumberFloat_float(self): jd = JDouble(1) _jpype.fault("PyJPNumberFloat_float") with self.assertRaisesRegex(SystemError, "fault"): float(jd) _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): float(jd) float(jd) @common.requireInstrumentation def testJPNumberFloat_str(self): jd = JDouble(1) _jpype.fault("PyJPNumberFloat_str") with self.assertRaisesRegex(SystemError, "fault"): str(jd) _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): str(jd) str(jd) @common.requireInstrumentation def testJPNumberFloat_repr(self): jd = JDouble(1) _jpype.fault("PyJPNumberFloat_repr") with self.assertRaisesRegex(SystemError, "fault"): repr(jd) _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): repr(jd) repr(jd) @common.requireInstrumentation def testJPNumberFloat_compare(self): jd = JDouble(1) _jpype.fault("PyJPNumberFloat_compare") with self.assertRaisesRegex(SystemError, "fault"): jd == 1 _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): jd == 1 jd == 1 @common.requireInstrumentation def testJPNumberFloat_hash(self): jd = JDouble(1) _jpype.fault("PyJPNumberFloat_hash") with self.assertRaises(SystemError): hash(jd) _jpype.fault("PyJPModule_getContext") with self.assertRaises(SystemError): hash(jd) hash(jd) @common.requireInstrumentation def testFault(self): _jpype.fault("JPDoubleType::findJavaConversion") with self.assertRaises(SystemError): JDouble(1.0) @common.requireInstrumentation def testConversionFault(self): _jpype.fault("JPDoubleType::findJavaConversion") with self.assertRaisesRegex(SystemError, "fault"): JDouble._canConvertToJava(object()) @common.requireInstrumentation def testArrayFault(self): ja = JArray(JDouble)(5) _jpype.fault("JPJavaFrame::NewDoubleArray") with self.assertRaisesRegex(SystemError, "fault"): JArray(JDouble)(1) _jpype.fault("JPJavaFrame::SetDoubleArrayRegion") with self.assertRaisesRegex(SystemError, "fault"): ja[0] = 0 _jpype.fault("JPJavaFrame::GetDoubleArrayRegion") with self.assertRaisesRegex(SystemError, "fault"): print(ja[0]) _jpype.fault("JPJavaFrame::GetDoubleArrayElements") # Special case, only BufferError is allowed from getBuffer with self.assertRaises(BufferError): memoryview(ja[0:3]) _jpype.fault("JPJavaFrame::ReleaseDoubleArrayElements") with self.assertRaisesRegex(SystemError, "fault"): ja[0:3] = bytes([1, 2, 3]) _jpype.fault("JPJavaFrame::ReleaseDoubleArrayElements") with self.assertRaisesRegex(SystemError, "fault"): jpype.JObject(ja[::2], jpype.JObject) _jpype.fault("JPJavaFrame::ReleaseDoubleArrayElements") def f(): # Special case no fault is allowed memoryview(ja[0:3]) f() _jpype.fault("JPDoubleType::setArrayRange") with self.assertRaisesRegex(SystemError, "fault"): ja[1:3] = [0, 0] def testFromJIntWiden(self): self.assertEqual(JDouble(JByte(123)), 123) self.assertEqual(JDouble(JShort(12345)), 12345) self.assertEqual(JDouble(JInt(123456789)), 123456789) self.assertEqual(JDouble(JLong(123456789)), 123456789) def testFromJFloatWiden(self): self.assertEqual(JDouble(JFloat(12345678)), 12345678) def testFromNone(self): with self.assertRaises(TypeError): JDouble(None) self.assertEqual(JDouble._canConvertToJava(None), "none") def testFromJDouble(self): self.assertEqual(JDouble(JDouble(1.2345)), 1.2345) def testUnBox(self): self.assertEqual(JDouble(java.lang.Double(1.2345)), 1.2345) def testFromFloat(self): self.assertEqual(JDouble(1.2345), 1.2345) self.assertEqual(JDouble._canConvertToJava(1.2345), "exact") def testFromLong(self): self.assertEqual(JDouble(12345), 12345) self.assertEqual(JDouble._canConvertToJava(12345), "implicit") def testFromObject(self): with self.assertRaises(TypeError): JDouble(object()) with self.assertRaises(TypeError): JDouble(JObject()) with self.assertRaises(TypeError): JDouble(JString("A")) self.assertEqual(JDouble._canConvertToJava(object()), "none") ja = JArray(JDouble)(5) with self.assertRaises(TypeError): ja[1] = object() jf = JClass("jpype.common.Fixture") with self.assertRaises(TypeError): jf.static_double_field = object() with self.assertRaises(TypeError): jf().double_field = object() def testCallDoubleFromNone(self): with self.assertRaises(TypeError): self.fixture.callDouble(None) with self.assertRaises(TypeError): self.fixture.static_double_field = None with self.assertRaises(TypeError): self.fixture.double_field = None def testThrow(self): with self.assertRaises(JException): self.fixture.throwDouble() with self.assertRaises(JException): self.cls.throwStaticDouble() with self.assertRaises(JException): self.fixture.throwStaticDouble() def checkType(self, q): # Check field self.fixture.double_field = q self.assertEqual(self.fixture.double_field, q) self.assertEqual(self.fixture.getDouble(), q) # Check static field self.cls.static_double_field = q self.assertEqual(self.fixture.static_double_field, q) self.assertEqual(self.fixture.getStaticDouble(), q) self.assertEqual(self.cls.getStaticDouble(), q) # Check call self.assertEqual(self.fixture.callDouble(q), q) self.assertEqual(self.cls.callStaticDouble(q), q) def testCheckInt(self): self.checkType(1) def testCheckFloat(self): self.checkType(2.0) def testCheckRange(self): self.checkType(float(1e340)) self.checkType(float(-1e340)) def testCheckNaN(self): import math nan = float("nan") self.assertTrue(math.isnan(self.fixture.callDouble(nan))) self.fixture.static_double_field = nan self.assertTrue(math.isnan(self.fixture.static_double_field)) self.fixture.double_field = nan self.assertTrue(math.isnan(self.fixture.double_field)) def testCheckInf(self): import math inf = float("inf") self.assertTrue(math.isinf(self.fixture.callDouble(inf))) self.fixture.static_double_field = inf self.assertTrue(math.isinf(self.fixture.static_double_field)) self.fixture.double_field = inf self.assertTrue(math.isinf(self.fixture.double_field)) def testCheckBool(self): self.checkType(True) self.checkType(False) def testCheckJBoolean(self): # FIXME fails # self.checkType(JBoolean(True)) # self.checkType(JBoolean(False)) pass def testCheckJChar(self): self.checkType(JChar("A")) def testCheckJByte(self): self.checkType(JByte(-128)) self.checkType(JByte(127)) def testCheckJShort(self): self.checkType(JShort(-2**15)) self.checkType(JShort(2**15 - 1)) def testCheckJInt(self): self.checkType(JInt(-2**31 + 1)) self.checkType(JInt(2**31 - 1)) def testCheckJLong(self): with self.useEqualityFunc(self.compareDoubleEqual): self.checkType(JLong(-2**63 + 1)) self.checkType(JLong(2**63 - 1)) def testCheckJFloat(self): self.checkType(JFloat(1.515313)) def testCheckDouble(self): self.checkType(JDouble(11.85193)) @common.requireNumpy def testCheckNumpyInt8(self): self.checkType(np.random.randint(-127, 128, dtype=np.int8)) self.checkType(np.random.randint(0, 255, dtype=np.uint8)) self.checkType(np.uint8(0)) self.checkType(np.uint8(255)) self.checkType(np.int8(-128)) self.checkType(np.int8(127)) @common.requireNumpy def testCheckNumpyInt16(self): self.checkType(np.random.randint(-2**15, 2**15 - 1, dtype=np.int16)) self.checkType(np.random.randint(0, 2**16 - 1, dtype=np.uint16)) self.checkType(np.uint16(0)) self.checkType(np.uint16(2**16 - 1)) self.checkType(np.int16(-2**15)) self.checkType(np.int16(2**15 - 1)) @common.requireNumpy def testCheckNumpyInt32(self): self.checkType(np.random.randint(-2**31, 2**31 - 1, dtype=np.int32)) self.checkType(np.random.randint(0, 2**32 - 1, dtype=np.uint32)) self.checkType(np.uint32(0)) self.checkType(np.uint32(2**32 - 1)) self.checkType(np.int32(-2**31)) self.checkType(np.int32(2**31 - 1)) @common.requireNumpy def testCheckNumpyInt64(self): self.checkType(np.random.randint(-2**63, 2**63 - 1, dtype=np.int64)) self.checkType( np.uint64(np.random.randint(0, 2**64 - 1, dtype=np.uint64))) self.checkType(np.uint64(0)) self.checkType(np.uint64(2**64 - 1)) self.checkType(np.int64(-2**63)) self.checkType(np.int64(2**63 - 1)) @common.requireNumpy def testCheckNumpyFloat32(self): self.checkType(np.float32(np.random.rand())) @common.requireNumpy def testCheckNumpyFloat64(self): self.checkType(np.float64(np.random.rand())) def testArrayConversionDouble(self): VALUES = [float(random.random()) for i in range(10)] jarr = JArray(JDouble)(VALUES) self.assertElementsAlmostEqual(VALUES, jarr) result = jarr[:] self.assertElementsAlmostEqual(VALUES, result) result = jarr[2:10] self.assertEqual(len(VALUES[2:10]), len(result)) self.assertElementsAlmostEqual(VALUES[2:10], result) # empty slice result = jarr[-1:3] expected = VALUES[-1:3] self.assertElementsAlmostEqual(expected, result) result = jarr[3:-2] expected = VALUES[3:-2] self.assertElementsEqual(expected, result) @common.requireNumpy def testArraySetFromNPDouble(self): a = np.random.random(100).astype(np.float64) jarr = JArray(JDouble)(100) jarr[:] = a self.assertElementsAlmostEqual(a, jarr) @common.requireNumpy def testArrayInitFromNPFloat(self): a = np.random.random(100).astype(np.float) jarr = JArray(JDouble)(a) self.assertElementsAlmostEqual(a, jarr) @common.requireNumpy def testArrayInitFromNPFloat32(self): a = np.random.random(100).astype(np.float32) jarr = JArray(JDouble)(a) self.assertElementsAlmostEqual(a, jarr) @common.requireNumpy def testArrayInitFromNPFloat64(self): a = np.random.random(100).astype(np.float64) jarr = JArray(JDouble)(a) self.assertElementsAlmostEqual(a, jarr) def testArraySetRange(self): ja = JArray(JDouble)(3) ja[0:1] = [123] self.assertEqual(ja[0], 123) ja[0:1] = [-1] self.assertEqual(ja[0], -1) ja[0:1] = [java.lang.Double(321)] self.assertEqual(ja[0], 321) with self.assertRaises(TypeError): ja[0:1] = [object()] def testArrayHash(self): ja = JArray(JDouble)([1, 2, 3]) self.assertIsInstance(hash(ja), int) @common.requireNumpy def testArrayBufferDims(self): ja = JArray(JDouble)(5) a = np.zeros((5, 2)) with self.assertRaisesRegex(TypeError, "incorrect"): ja[:] = a def testArrayBadItem(self): class q(object): def __float__(self): raise SystemError("nope") ja = JArray(JDouble)(5) a = [1, -1, q(), 3, 4] with self.assertRaisesRegex(SystemError, "nope"): ja[:] = a def testArrayBadDims(self): class q(bytes): # Lie about our length def __len__(self): return 5 a = q([1, 2, 3]) ja = JArray(JDouble)(5) with self.assertRaisesRegex(ValueError, "Slice"): ja[:] = [1, 2, 3] with self.assertRaisesRegex(ValueError, "mismatch"): ja[:] = a def testCastBoolean(self): self.assertEqual(JDouble._canConvertToJava(JBoolean(True)), "none") jpype-1.3.0/test/jpypetest/test_jedi.py000066400000000000000000000051361405671516700202150ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import sys import jpype import common import types import functools import inspect have_jedi = False try: import jedi have_jedi = (common.version(jedi.__version__) > (0, 14)) except: pass # FIXME: some jedi version is causing an issue jpype-project/jpype#920 so we pretend not to have jedi, until it is resolved. have_jedi = False class JediTestCase(common.JPypeTestCase): """Test tab completion on JPype objects """ def setUp(self): common.JPypeTestCase.setUp(self) if common.fast: raise common.unittest.SkipTest("fast") self.cls = jpype.JClass('java.lang.String') self.obj = self.cls('foo') @common.unittest.skipUnless(have_jedi, "jedi not available") def testCompleteClass(self): src = 'self.obj.con' script = jedi.Interpreter(src, [locals()]) compl = [i.name for i in script.complete()] self.assertEqual(compl, ['concat', 'contains', 'contentEquals']) @common.unittest.skipUnless(have_jedi, "jedi not available") def testCompleteMethod(self): src = 'self.obj.substring(1).con' script = jedi.Interpreter(src, [locals()]) compl = [i.name for i in script.complete()] self.assertEqual(compl, ['concat', 'contains', 'contentEquals']) @common.unittest.skipUnless(have_jedi, "jedi not available") def testCompleteField(self): src = 'self.obj.CASE_INSENSITIVE_ORDER.wa' script = jedi.Interpreter(src, [locals()]) compl = [i.name for i in script.complete()] self.assertEqual(compl, ['wait']) @common.unittest.skipUnless(have_jedi, "jedi not available") def testCompleteMethodField(self): src = 'self.obj.substring(1).CAS' script = jedi.Interpreter(src, [locals()]) compl = [i.name for i in script.complete()] self.assertEqual(compl, ['CASE_INSENSITIVE_ORDER']) jpype-1.3.0/test/jpypetest/test_jfloat.py000066400000000000000000000360351405671516700205630ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import sys import jpype import common import random import _jpype import jpype from jpype import java from jpype.types import * try: import numpy as np except ImportError: pass class JFloatTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) self.value = 1.0 + 1.0 / 65536 self.cls = JClass("jpype.common.Fixture") self.fixture = self.cls() def compareFloatEqual(self, x, y, msg=None): if x == y: return if x < 0: x = -x if y < 0: y = -y a = (x + y) / 2 b = (x - y) if b < 0: b = -b if b < a * 1e-7: return msg = self._formatMessage(msg, '%s == %s' % (safe_repr(first), safe_repr(second))) raise self.failureException(msg) @common.requireInstrumentation def testJPNumberFloat_int(self): jd = JFloat(1) _jpype.fault("PyJPNumberFloat_int") with self.assertRaisesRegex(SystemError, "fault"): int(jd) _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): int(jd) int(jd) @common.requireInstrumentation def testJPNumberFloat_float(self): jd = JFloat(1) _jpype.fault("PyJPNumberFloat_float") with self.assertRaisesRegex(SystemError, "fault"): float(jd) _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): float(jd) float(jd) @common.requireInstrumentation def testJPNumberFloat_str(self): jd = JFloat(1) _jpype.fault("PyJPNumberFloat_str") with self.assertRaisesRegex(SystemError, "fault"): str(jd) _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): str(jd) str(jd) @common.requireInstrumentation def testJPNumberFloat_repr(self): jd = JFloat(1) _jpype.fault("PyJPNumberFloat_repr") with self.assertRaisesRegex(SystemError, "fault"): repr(jd) _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): repr(jd) repr(jd) @common.requireInstrumentation def testJPNumberFloat_compare(self): jd = JFloat(1) _jpype.fault("PyJPNumberFloat_compare") with self.assertRaisesRegex(SystemError, "fault"): jd == 1 _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): jd == 1 jd == 1 @common.requireInstrumentation def testJPNumberFloat_hash(self): jd = JFloat(1) _jpype.fault("PyJPNumberFloat_hash") with self.assertRaises(SystemError): hash(jd) _jpype.fault("PyJPModule_getContext") with self.assertRaises(SystemError): hash(jd) hash(jd) @common.requireInstrumentation def testFault(self): _jpype.fault("JPFloatType::findJavaConversion") with self.assertRaises(SystemError): JFloat(1.0) @common.requireInstrumentation def testConversionFault(self): _jpype.fault("JPFloatType::findJavaConversion") with self.assertRaisesRegex(SystemError, "fault"): JFloat._canConvertToJava(object()) @common.requireInstrumentation def testArrayFault(self): ja = JArray(JFloat)(5) _jpype.fault("JPJavaFrame::NewFloatArray") with self.assertRaisesRegex(SystemError, "fault"): JArray(JFloat)(1) _jpype.fault("JPJavaFrame::SetFloatArrayRegion") with self.assertRaisesRegex(SystemError, "fault"): ja[0] = 0 _jpype.fault("JPJavaFrame::GetFloatArrayRegion") with self.assertRaisesRegex(SystemError, "fault"): print(ja[0]) _jpype.fault("JPJavaFrame::GetFloatArrayElements") # Special case, only BufferError is allowed from getBuffer with self.assertRaises(BufferError): memoryview(ja[0:3]) _jpype.fault("JPJavaFrame::ReleaseFloatArrayElements") with self.assertRaisesRegex(SystemError, "fault"): ja[0:3] = bytes([1, 2, 3]) _jpype.fault("JPJavaFrame::ReleaseFloatArrayElements") with self.assertRaisesRegex(SystemError, "fault"): jpype.JObject(ja[::2], jpype.JObject) _jpype.fault("JPJavaFrame::ReleaseFloatArrayElements") def f(): # Special case no fault is allowed memoryview(ja[0:3]) f() _jpype.fault("JPFloatType::setArrayRange") with self.assertRaisesRegex(SystemError, "fault"): ja[1:3] = [0, 0] def testFromJIntWiden(self): self.assertEqual(JFloat(JByte(123)), 123) self.assertEqual(JFloat(JShort(12345)), 12345) self.assertEqual(JFloat(JInt(12345678)), 12345678) self.assertEqual(JFloat(JLong(12345678)), 12345678) def testFromJFloatWiden(self): self.assertEqual(JFloat(JDouble(12345678)), 12345678) def testFromNone(self): with self.assertRaises(TypeError): JFloat(None) self.assertEqual(JFloat._canConvertToJava(None), "none") def testFromJFloat(self): with self.useEqualityFunc(self.compareFloatEqual): self.assertEqual(JFloat(JFloat(1.2345)), 1.2345) def testFromJDouble(self): with self.useEqualityFunc(self.compareFloatEqual): self.assertEqual(JFloat(JDouble(1.2345)), 1.2345) def testUnBox(self): pass # with self.useEqualityFunc(self.foo): # self.assertEqual(JFloat(java.lang.Double(1.2345)), 1.2345) def testFromFloat(self): with self.useEqualityFunc(self.compareFloatEqual): self.assertEqual(JFloat(1.2345), 1.2345) self.assertEqual(JFloat._canConvertToJava(1.2345), "implicit") def testFromLong(self): self.assertEqual(JFloat(12345), 12345) self.assertEqual(JFloat._canConvertToJava(12345), "implicit") def testFromObject(self): with self.assertRaises(TypeError): JFloat(object()) with self.assertRaises(TypeError): JFloat(JObject()) with self.assertRaises(TypeError): JFloat(JString("A")) self.assertEqual(JFloat._canConvertToJava(object()), "none") ja = JArray(JFloat)(5) with self.assertRaises(TypeError): ja[1] = object() jf = JClass("jpype.common.Fixture") with self.assertRaises(TypeError): jf.static_float_field = object() with self.assertRaises(TypeError): jf().float_field = object() def testCallFloatFromNone(self): with self.assertRaises(TypeError): self.fixture.callFloat(None) with self.assertRaises(TypeError): self.fixture.static_float_field = None with self.assertRaises(TypeError): self.fixture.float_field = None def checkType(self, q): # Check field self.fixture.float_field = q self.assertEqual(self.fixture.float_field, q) self.assertEqual(self.fixture.getFloat(), q) # Check static field self.cls.static_float_field = q self.assertEqual(self.fixture.static_float_field, q) self.assertEqual(self.fixture.getStaticFloat(), q) self.assertEqual(self.cls.getStaticFloat(), q) # Check call self.assertEqual(self.fixture.callFloat(q), q) self.assertEqual(self.cls.callStaticFloat(q), q) # Check throw with self.assertRaises(JException): self.fixture.throwFloat() with self.assertRaises(JException): self.cls.throwStaticFloat() with self.assertRaises(JException): self.fixture.throwStaticFloat() def testCheckInt(self): self.checkType(1) def testCheckFloat(self): self.checkType(2.0) def testCheckRange(self): self.checkType(float(1e340)) self.checkType(float(-1e340)) def testCheckNaN(self): import math nan = float("nan") self.assertTrue(math.isnan(self.fixture.callFloat(nan))) self.fixture.static_float_field = nan self.assertTrue(math.isnan(self.fixture.static_float_field)) self.fixture.float_field = nan self.assertTrue(math.isnan(self.fixture.float_field)) def testCheckInf(self): import math inf = float("inf") self.assertTrue(math.isinf(self.fixture.callFloat(inf))) self.fixture.static_float_field = inf self.assertTrue(math.isinf(self.fixture.static_float_field)) self.fixture.float_field = inf self.assertTrue(math.isinf(self.fixture.float_field)) def testCheckBool(self): self.checkType(True) self.checkType(False) def testCheckJBoolean(self): # FIXME fails # self.checkType(JBoolean(True)) # self.checkType(JBoolean(False)) pass def testCheckJChar(self): self.checkType(JChar("A")) def testCheckJByte(self): self.checkType(JByte(-128)) self.checkType(JByte(127)) def testCheckJShort(self): self.checkType(JShort(-2**15)) self.checkType(JShort(2**15 - 1)) def testCheckJInt(self): with self.useEqualityFunc(self.compareFloatEqual): self.checkType(JInt(-2**31 + 1)) self.checkType(JInt(2**31 - 1)) def testCheckJLong(self): with self.useEqualityFunc(self.compareFloatEqual): self.checkType(JLong(-2**63 + 1)) self.checkType(JLong(2**63 - 1)) def testCheckJFloat(self): self.checkType(JFloat(1.515313)) @common.requireNumpy def testCheckNumpyInt8(self): self.checkType(np.random.randint(-127, 128, dtype=np.int8)) self.checkType(np.random.randint(0, 255, dtype=np.uint8)) self.checkType(np.uint8(0)) self.checkType(np.uint8(255)) self.checkType(np.int8(-128)) self.checkType(np.int8(127)) @common.requireNumpy def testCheckNumpyInt16(self): self.checkType(np.random.randint(-2**15, 2**15 - 1, dtype=np.int16)) self.checkType(np.random.randint(0, 2**16 - 1, dtype=np.uint16)) self.checkType(np.uint16(0)) self.checkType(np.uint16(2**16 - 1)) self.checkType(np.int16(-2**15)) self.checkType(np.int16(2**15 - 1)) @common.requireNumpy def testCheckNumpyInt32(self): with self.useEqualityFunc(self.compareFloatEqual): self.checkType(np.random.randint(-2**31, 2**31 - 1, dtype=np.int32)) self.checkType(np.random.randint(0, 2**32 - 1, dtype=np.uint32)) self.checkType(np.uint32(0)) self.checkType(np.uint32(2**32 - 1)) self.checkType(np.int32(-2**31)) self.checkType(np.int32(2**31 - 1)) @common.requireNumpy def testCheckNumpyInt64(self): with self.useEqualityFunc(self.compareFloatEqual): self.checkType(np.random.randint(-2**63, 2**63 - 1, dtype=np.int64)) self.checkType( np.uint64(np.random.randint(0, 2**64 - 1, dtype=np.uint64))) self.checkType(np.uint64(0)) self.checkType(np.uint64(2**64 - 1)) self.checkType(np.int64(-2**63)) self.checkType(np.int64(2**63 - 1)) @common.requireNumpy def testCheckNumpyFloat32(self): self.checkType(np.float32(np.random.rand())) @common.requireNumpy def testCheckNumpyFloat64(self): with self.useEqualityFunc(self.compareFloatEqual): self.checkType(np.float64(np.random.rand())) def testArrayConversionDouble(self): VALUES = [float(random.random()) for i in range(100)] jarr = JArray(JFloat)(VALUES) self.assertElementsAlmostEqual(VALUES, jarr) result = jarr[:] self.assertElementsAlmostEqual(VALUES, result) result = jarr[2:10] self.assertEqual(len(VALUES[2:10]), len(result)) self.assertElementsAlmostEqual(VALUES[2:10], result) # empty slice result = jarr[-1:3] expected = VALUES[-1:3] self.assertElementsAlmostEqual(expected, result) result = jarr[3:-2] expected = VALUES[3:-2] self.assertElementsAlmostEqual(expected, result) @common.requireNumpy def testArraySetFromNPDouble(self): a = np.random.random(100).astype(np.float64) jarr = JArray(JFloat)(100) jarr[:] = a self.assertElementsAlmostEqual(a, jarr) @common.requireNumpy def testArrayInitFromNPFloat(self): a = np.random.random(100).astype(np.float) jarr = JArray(JFloat)(a) self.assertElementsAlmostEqual(a, jarr) @common.requireNumpy def testArrayInitFromNPFloat32(self): a = np.random.random(100).astype(np.float32) jarr = JArray(JFloat)(a) self.assertElementsAlmostEqual(a, jarr) @common.requireNumpy def testArrayInitFromNPFloat64(self): a = np.random.random(100).astype(np.float64) jarr = JArray(JFloat)(a) self.assertElementsAlmostEqual(a, jarr) def testArraySetRange(self): ja = JArray(JFloat)(3) ja[0:1] = [123] self.assertEqual(ja[0], 123) ja[0:1] = [-1] self.assertEqual(ja[0], -1) ja[0:1] = [java.lang.Double(321)] self.assertEqual(ja[0], 321) with self.assertRaises(TypeError): ja[0:1] = [object()] def testArrayHash(self): ja = JArray(JFloat)([1, 2, 3]) self.assertIsInstance(hash(ja), int) @common.requireNumpy def testArrayBufferDims(self): ja = JArray(JFloat)(5) a = np.zeros((5, 2)) with self.assertRaisesRegex(TypeError, "incorrect"): ja[:] = a def testArrayBadItem(self): class q(object): def __float__(self): raise SystemError("nope") ja = JArray(JFloat)(5) a = [1, -1, q(), 3, 4] with self.assertRaisesRegex(SystemError, "nope"): ja[:] = a def testArrayBadDims(self): class q(bytes): # Lie about our length def __len__(self): return 5 a = q([1, 2, 3]) ja = JArray(JFloat)(5) with self.assertRaisesRegex(ValueError, "Slice"): ja[:] = [1, 2, 3] with self.assertRaisesRegex(ValueError, "mismatch"): ja[:] = a jpype-1.3.0/test/jpypetest/test_jint.py000066400000000000000000000464521405671516700202540ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import sys import jpype import common import random import _jpype import jpype from jpype import java from jpype.types import * try: import numpy as np except ImportError: pass VALUES = [random.randint(-2**31, 2**31 - 1) for i in range(10)] class JIntTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) self.cls = JClass("jpype.common.Fixture") self.fixture = self.cls() @common.requireInstrumentation def testJPNumberLong_int(self): jd = JInt(1) _jpype.fault("PyJPNumberLong_int") with self.assertRaisesRegex(SystemError, "fault"): int(jd) _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): int(jd) int(jd) @common.requireInstrumentation def testJPNumberLong_float(self): jd = JInt(1) _jpype.fault("PyJPNumberLong_float") with self.assertRaisesRegex(SystemError, "fault"): float(jd) _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): float(jd) float(jd) @common.requireInstrumentation def testJPNumberLong_str(self): jd = JInt(1) _jpype.fault("PyJPNumberLong_str") with self.assertRaisesRegex(SystemError, "fault"): str(jd) _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): str(jd) str(jd) @common.requireInstrumentation def testJPNumberLong_repr(self): jd = JInt(1) _jpype.fault("PyJPNumberLong_repr") with self.assertRaisesRegex(SystemError, "fault"): repr(jd) _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): repr(jd) repr(jd) @common.requireInstrumentation def testJPNumberLong_compare(self): jd = JInt(1) _jpype.fault("PyJPNumberLong_compare") with self.assertRaisesRegex(SystemError, "fault"): jd == 1 _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): jd == 1 jd == 1 @common.requireInstrumentation def testJPNumberLong_hash(self): jd = JInt(1) _jpype.fault("PyJPNumberLong_hash") with self.assertRaises(SystemError): hash(jd) _jpype.fault("PyJPModule_getContext") with self.assertRaises(SystemError): hash(jd) hash(jd) @common.requireInstrumentation def testFault(self): _jpype.fault("JPIntType::findJavaConversion") with self.assertRaises(SystemError): JInt(1.0) @common.requireInstrumentation def testConversionFault(self): _jpype.fault("JPIntType::findJavaConversion") with self.assertRaisesRegex(SystemError, "fault"): JInt._canConvertToJava(object()) @common.requireInstrumentation def testArrayFault(self): ja = JArray(JInt)(5) _jpype.fault("JPJavaFrame::NewIntArray") with self.assertRaisesRegex(SystemError, "fault"): JArray(JInt)(1) _jpype.fault("JPJavaFrame::SetIntArrayRegion") with self.assertRaisesRegex(SystemError, "fault"): ja[0] = 0 _jpype.fault("JPJavaFrame::GetIntArrayRegion") with self.assertRaisesRegex(SystemError, "fault"): print(ja[0]) _jpype.fault("JPJavaFrame::GetIntArrayElements") # Special case, only BufferError is allowed from getBuffer with self.assertRaises(BufferError): memoryview(ja[0:3]) _jpype.fault("JPJavaFrame::ReleaseIntArrayElements") with self.assertRaisesRegex(SystemError, "fault"): ja[0:3] = bytes([1, 2, 3]) _jpype.fault("JPJavaFrame::ReleaseIntArrayElements") with self.assertRaisesRegex(SystemError, "fault"): jpype.JObject(ja[::2], jpype.JObject) _jpype.fault("JPJavaFrame::ReleaseIntArrayElements") def f(): # Special case no fault is allowed memoryview(ja[0:3]) f() _jpype.fault("JPIntType::setArrayRange") with self.assertRaisesRegex(SystemError, "fault"): ja[1:3] = [0, 0] def testFromJIntWiden(self): self.assertEqual(JInt(JByte(123)), 123) self.assertEqual(JInt(JShort(12345)), 12345) self.assertEqual(JInt(JInt(12345678)), 12345678) self.assertEqual(JInt(JLong(12345678)), 12345678) def testFromJIntWiden(self): self.assertEqual(JInt(JDouble(12345678)), 12345678) def testFromNone(self): with self.assertRaises(TypeError): JInt(None) self.assertEqual(JInt._canConvertToJava(None), "none") def testUnBox(self): self.assertEqual(JInt(java.lang.Double(1.2345)), 1) def testFromFloat(self): self.assertEqual(JInt._canConvertToJava(1.2345), "explicit") @jpype.JImplements("java.util.function.IntSupplier") class q(object): @jpype.JOverride def getAsInt(self): return 4.5 # this will hit explicit conversion self.assertEqual(JObject(q()).getAsInt(), 4) def testFromLong(self): self.assertEqual(JInt(12345), 12345) self.assertEqual(JInt._canConvertToJava(12345), "implicit") def testFromObject(self): with self.assertRaises(TypeError): JInt(object()) with self.assertRaises(TypeError): JInt(JObject()) with self.assertRaises(TypeError): JInt(JString("A")) self.assertEqual(JInt._canConvertToJava(object()), "none") ja = JArray(JInt)(5) with self.assertRaises(TypeError): ja[1] = object() jf = JClass("jpype.common.Fixture") with self.assertRaises(TypeError): jf.static_int_field = object() with self.assertRaises(TypeError): jf().int_field = object() def testCallFloatFromNone(self): with self.assertRaises(TypeError): self.fixture.callFloat(None) with self.assertRaises(TypeError): self.fixture.static_int_field = None with self.assertRaises(TypeError): self.fixture.int_field = None def testThrow(self): # Check throw with self.assertRaises(JException): self.fixture.throwInt() with self.assertRaises(JException): self.cls.throwStaticInt() with self.assertRaises(JException): self.fixture.throwStaticInt() def checkType(self, q): # Check field self.fixture.int_field = q self.assertEqual(self.fixture.int_field, q) self.assertEqual(self.fixture.getInt(), q) # Check static field self.cls.static_int_field = q self.assertEqual(self.fixture.static_int_field, q) self.assertEqual(self.fixture.getStaticInt(), q) self.assertEqual(self.cls.getStaticInt(), q) # Check call self.assertEqual(self.fixture.callInt(q), q) self.assertEqual(self.cls.callStaticInt(q), q) def checkTypeFail(self, q, exc=TypeError): with self.assertRaises(exc): self.fixture.int_field = q with self.assertRaises(exc): self.fixture.callInt(q) with self.assertRaises(exc): self.fixture.callStaticInt(q) def testCastFloat(self): self.fixture.int_field = JInt(6.0) self.assertEqual(self.fixture.int_field, 6) def testCheckInt(self): self.checkType(1) def testCheckFloat(self): self.checkTypeFail(2.0) def testCheckRange(self): self.checkType(2**31 - 1) self.checkType(-2**31) self.checkTypeFail(2**31, exc=OverflowError) self.checkTypeFail(-2**31 - 1, exc=OverflowError) def testExplicitRange(self): # These will not overflow as they are explicit casts self.assertEqual(JInt(2**32), 0) self.assertEqual(JInt(-2**32), 0) def testCheckBool(self): self.checkType(True) self.checkType(False) def testCheckJBoolean(self): self.checkTypeFail(JBoolean(True)) self.checkTypeFail(JBoolean(False)) def testCheckJChar(self): self.checkType(JChar("A")) def testCheckJByte(self): self.checkType(JByte(-128)) self.checkType(JByte(127)) def testCheckJShort(self): self.checkType(JShort(-2**15)) self.checkType(JShort(2**15 - 1)) def testCheckJInt(self): self.checkType(JInt(-2**31 + 1)) self.checkType(JInt(2**31 - 1)) def testCheckJLong(self): self.checkTypeFail(JLong(-2**63 + 1)) self.checkTypeFail(JLong(2**63 - 1)) @common.requireNumpy def testCheckNumpyInt8(self): self.checkType(np.random.randint(-127, 128, dtype=np.int8)) self.checkType(np.random.randint(0, 255, dtype=np.uint8)) self.checkType(np.uint8(0)) self.checkType(np.uint8(255)) self.checkType(np.int8(-128)) self.checkType(np.int8(127)) @common.requireNumpy def testCheckNumpyInt16(self): self.checkType(np.random.randint(-2**15, 2**15 - 1, dtype=np.int16)) self.checkType(np.random.randint(0, 2**16 - 1, dtype=np.uint16)) self.checkType(np.uint16(0)) self.checkType(np.uint16(2**16 - 1)) self.checkType(np.int16(-2**15)) self.checkType(np.int16(2**15 - 1)) @common.requireNumpy def testCheckNumpyInt32(self): self.checkType(np.uint32(0)) self.checkTypeFail(np.uint32(2**32 - 1), exc=OverflowError) self.checkType(np.int32(-2**31)) self.checkType(np.int32(2**31 - 1)) @common.requireNumpy def testCheckNumpyInt64(self): #self.checkTypeFail(np.random.randint(-2**63,2**63-1, dtype=np.int64)) # FIXME OverflowError #self.checkType(np.uint64(np.random.randint(0,2**64-1, dtype=np.uint64))) # FIXME OverflowError # self.checkType(np.uint64(2**64-1)) self.checkTypeFail(np.int64(-2**63), OverflowError) self.checkTypeFail(np.int64(2**63 - 1), OverflowError) @common.requireNumpy def testCheckNumpyFloat32(self): self.checkTypeFail(np.float32(np.random.rand())) @common.requireNumpy def testCheckNumpyFloat64(self): self.checkTypeFail(np.float64(np.random.rand())) def checkArrayType(self, a, expected): # Check init ja = JArray(JInt)(a) self.assertElementsEqual(ja, expected) ja = JArray(JInt)(len(a)) ja[:] = a self.assertElementsEqual(ja, expected) return ja def checkArrayTypeFail(self, a): # Check init ja = JArray(JInt)(a) ja = JArray(JInt)(len(a)) ja[:] = a def testArrayConversion(self): a = [random.randint(-2**31, 2**31) for i in range(100)] jarr = self.checkArrayType(a, a) result = jarr[2:10] self.assertEqual(len(a[2:10]), len(result)) self.assertElementsAlmostEqual(a[2:10], result) # empty slice result = jarr[-1:3] expected = a[-1:3] self.assertElementsAlmostEqual(expected, result) result = jarr[3:-2] expected = a[3:-2] self.assertElementsAlmostEqual(expected, result) @common.requireNumpy def testArrayInitFromNPInt(self): a = np.random.randint(-2**31, 2**31 - 1, size=100, dtype=np.int) self.checkArrayType(a, a) @common.requireNumpy def testArrayInitFromNPInt8(self): a = np.random.randint(-2**7, 2**7 - 1, size=100, dtype=np.int8) self.checkArrayType(a, a) @common.requireNumpy def testArrayInitFromNPInt16(self): a = np.random.randint(-2**15, 2**15 - 1, size=100, dtype=np.int16) self.checkArrayType(a, a) @common.requireNumpy def testArrayInitFromNPInt32(self): a = np.random.randint(-2**31, 2**31 - 1, size=100, dtype=np.int32) self.checkArrayType(a, a) @common.requireNumpy def testArrayInitFromNPInt64(self): a = np.random.randint(-2**63, 2**63 - 1, size=100, dtype=np.int64) self.checkArrayType(a, a.astype(np.int32)) @common.requireNumpy def testArrayInitFromNPFloat32(self): a = np.random.random(100).astype(np.float32) self.checkArrayType(a, a.astype(np.int32)) @common.requireNumpy def testArrayInitFromNPFloat64(self): a = np.random.random(100).astype(np.float64) self.checkArrayType(a, a.astype(np.int32)) def testArraySetRange(self): ja = JArray(JInt)(3) ja[0:1] = [123] self.assertEqual(ja[0], 123) ja[0:1] = [-1] self.assertEqual(ja[0], -1) with self.assertRaises(TypeError): ja[0:1] = [1.000] with self.assertRaises(TypeError): ja[0:1] = [java.lang.Double(321)] with self.assertRaises(TypeError): ja[0:1] = [object()] def testArrayConversionFail(self): jarr = JArray(JInt)(VALUES) with self.assertRaises(TypeError): jarr[1] = 'a' def testArraySliceLength(self): jarr = JArray(JInt)(VALUES) jarr[1:2] = [1] with self.assertRaises(ValueError): jarr[1:2] = [1, 2, 3] def testArrayConversionInt(self): jarr = JArray(JInt)(VALUES) result = jarr[0: len(jarr)] self.assertElementsEqual(VALUES, result) result = jarr[2:10] self.assertElementsEqual(VALUES[2:10], result) def testArrayConversionError(self): jarr = JArray(JInt, 1)(10) with self.assertRaises(TypeError): jarr[1:2] = [dict()] # -1 is returned by python, if conversion fails also, ensure this works jarr[1:2] = [-1] def testArrayClone(self): array = JArray(JInt, 2)([[1, 2], [3, 4]]) carray = array.clone() # Verify the first dimension is cloned self.assertFalse(array.equals(carray)) # Copy is shallow self.assertTrue(array[0].equals(carray[0])) def testArrayGetSlice(self): contents = VALUES array = JArray(JInt)(contents) self.assertEqual(list(array[1:]), contents[1:]) self.assertEqual(list(array[:-1]), contents[:-1]) self.assertEqual(list(array[1:-1]), contents[1:-1]) def testArraySetSlice(self): contents = [1, 2, 3, 4] array = JArray(JInt)(contents) array[1:] = [5, 6, 7] contents[1:] = [5, 6, 7] self.assertEqual(list(array[:]), contents[:]) array[:-1] = [8, 9, 10] contents[:-1] = [8, 9, 10] self.assertEqual(list(array[:]), contents[:]) def testArrayGetSliceStep(self): contents = VALUES array = JArray(JInt)(contents) self.assertEqual(list(array[::2]), contents[::2]) self.assertEqual(list(array[::3]), contents[::3]) self.assertEqual(list(array[::4]), contents[::4]) self.assertEqual(list(array[::5]), contents[::5]) self.assertEqual(list(array[::6]), contents[::6]) self.assertEqual(list(array[::7]), contents[::7]) self.assertEqual(list(array[::8]), contents[::8]) self.assertEqual(list(array[1::3]), contents[1::3]) self.assertEqual(list(array[1:-2:3]), contents[1:-2:3]) def testArraySliceStepNeg(self): contents = VALUES array = JArray(JInt)(contents) self.assertEqual(list(array[::-1]), contents[::-1]) self.assertEqual(list(array[::-2]), contents[::-2]) self.assertEqual(list(array[::-3]), contents[::-3]) self.assertEqual(list(array[::-4]), contents[::-4]) self.assertEqual(list(array[::-5]), contents[::-5]) self.assertEqual(list(array[::-6]), contents[::-6]) self.assertEqual(list(array[2::-3]), contents[2::-3]) self.assertEqual(list(array[-2::-3]), contents[-2::-3]) def testArraySetArraySliceStep(self): contents = [1, 2, 3, 4, 5, 6] array = JArray(JInt)(contents) array[::2] = [5, 6, 7] contents[::2] = [5, 6, 7] self.assertEqual(list(array[:]), contents[:]) def testArrayEquals(self): contents = VALUES array = JArray(JInt)(contents) array2 = JArray(JInt)(contents) self.assertEqual(array, array) self.assertNotEqual(array, array2) def testArrayIter(self): contents = VALUES array = JArray(JInt)(contents) contents2 = [i for i in array] self.assertEqual(contents, contents2) def testArrayGetOutOfBounds(self): contents = [1, 2, 3, 4] array = JArray(JInt)(contents) with self.assertRaises(IndexError): array[5] self.assertEqual(array[-1], contents[-1]) self.assertEqual(array[-4], contents[-4]) with self.assertRaises(IndexError): array[-5] def testArraySetOutOfBounds(self): contents = [1, 2, 3, 4] array = JArray(JInt)(contents) with self.assertRaises(IndexError): array[5] = 1 array[-1] = 5 contents[-1] = 5 array[-4] = 6 contents[-4] = 6 self.assertEqual(list(array[:]), contents) with self.assertRaises(IndexError): array[-5] = 1 def testArraySliceCast(self): JA = JArray(JInt) ja = JA(VALUES) ja2 = ja[::2] jo = jpype.JObject(ja2, jpype.JObject) ja3 = jpype.JObject(jo, JA) self.assertEqual(type(jo), jpype.JClass("java.lang.Object")) self.assertEqual(type(ja2), JA) self.assertEqual(type(ja3), JA) self.assertEqual(list(ja2), list(ja3)) def testArrayReverse(self): n = list(VALUES) ja = JArray(JInt)(n) a = [i for i in reversed(ja)] n = [i for i in reversed(n)] self.assertEqual(a, n) def testArrayHash(self): ja = JArray(JInt)([1, 2, 3]) self.assertIsInstance(hash(ja), int) @common.requireNumpy def testArrayBufferDims(self): ja = JArray(JInt)(5) a = np.zeros((5, 2)) with self.assertRaisesRegex(TypeError, "incorrect"): ja[:] = a def testArrayBadItem(self): class q(object): def __int__(self): raise SystemError("nope") def __index__(self): raise SystemError("nope") ja = JArray(JInt)(5) a = [1, -1, q(), 3, 4] with self.assertRaisesRegex(SystemError, "nope"): ja[:] = a def testArrayBadDims(self): class q(bytes): # Lie about our length def __len__(self): return 5 a = q([1, 2, 3]) ja = JArray(JInt)(5) with self.assertRaisesRegex(ValueError, "Slice"): ja[:] = [1, 2, 3] with self.assertRaisesRegex(ValueError, "mismatch"): ja[:] = a jpype-1.3.0/test/jpypetest/test_jlong.py000066400000000000000000000465001405671516700204130ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import sys import jpype import common import random import _jpype import jpype from jpype import java from jpype.types import * try: import numpy as np except ImportError: pass VALUES = [random.randint(-2**63, 2**63 - 1) for i in range(10)] class JLongTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) self.cls = JClass("jpype.common.Fixture") self.fixture = self.cls() @common.requireInstrumentation def testJPNumberLong_int(self): jd = JLong(1) _jpype.fault("PyJPNumberLong_int") with self.assertRaisesRegex(SystemError, "fault"): int(jd) _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): int(jd) int(jd) @common.requireInstrumentation def testJPNumberLong_float(self): jd = JLong(1) _jpype.fault("PyJPNumberLong_float") with self.assertRaisesRegex(SystemError, "fault"): float(jd) _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): float(jd) float(jd) @common.requireInstrumentation def testJPNumberLong_str(self): jd = JLong(1) _jpype.fault("PyJPNumberLong_str") with self.assertRaisesRegex(SystemError, "fault"): str(jd) _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): str(jd) str(jd) @common.requireInstrumentation def testJPNumberLong_repr(self): jd = JLong(1) _jpype.fault("PyJPNumberLong_repr") with self.assertRaisesRegex(SystemError, "fault"): repr(jd) _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): repr(jd) repr(jd) @common.requireInstrumentation def testJPNumberLong_compare(self): jd = JLong(1) _jpype.fault("PyJPNumberLong_compare") with self.assertRaisesRegex(SystemError, "fault"): jd == 1 _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): jd == 1 jd == 1 @common.requireInstrumentation def testJPNumberLong_hash(self): jd = JLong(1) _jpype.fault("PyJPNumberLong_hash") with self.assertRaises(SystemError): hash(jd) _jpype.fault("PyJPModule_getContext") with self.assertRaises(SystemError): hash(jd) hash(jd) @common.requireInstrumentation def testFault(self): _jpype.fault("JPLongType::findJavaConversion") with self.assertRaises(SystemError): JLong(1.0) @common.requireInstrumentation def testConversionFault(self): _jpype.fault("JPLongType::findJavaConversion") with self.assertRaisesRegex(SystemError, "fault"): JLong._canConvertToJava(object()) @common.requireInstrumentation def testArrayFault(self): ja = JArray(JLong)(5) _jpype.fault("JPJavaFrame::NewLongArray") with self.assertRaisesRegex(SystemError, "fault"): JArray(JLong)(1) _jpype.fault("JPJavaFrame::SetLongArrayRegion") with self.assertRaisesRegex(SystemError, "fault"): ja[0] = 0 _jpype.fault("JPJavaFrame::GetLongArrayRegion") with self.assertRaisesRegex(SystemError, "fault"): print(ja[0]) _jpype.fault("JPJavaFrame::GetLongArrayElements") # Special case, only BufferError is allowed from getBuffer with self.assertRaises(BufferError): memoryview(ja[0:3]) _jpype.fault("JPJavaFrame::ReleaseLongArrayElements") with self.assertRaisesRegex(SystemError, "fault"): ja[0:3] = bytes([1, 2, 3]) _jpype.fault("JPJavaFrame::ReleaseLongArrayElements") with self.assertRaisesRegex(SystemError, "fault"): jpype.JObject(ja[::2], jpype.JObject) _jpype.fault("JPJavaFrame::ReleaseLongArrayElements") def f(): # Special case no fault is allowed memoryview(ja[0:3]) f() _jpype.fault("JPLongType::setArrayRange") with self.assertRaisesRegex(SystemError, "fault"): ja[1:3] = [0, 0] def testFromJLongWiden(self): self.assertEqual(JLong(JByte(123)), 123) self.assertEqual(JLong(JShort(12345)), 12345) self.assertEqual(JLong(JInt(12345678)), 12345678) self.assertEqual(JLong(JLong(12345678)), 12345678) def testFromJLongWiden(self): self.assertEqual(JLong(JDouble(12345678)), 12345678) def testFromNone(self): with self.assertRaises(TypeError): JLong(None) self.assertEqual(JLong._canConvertToJava(None), "none") def testUnBox(self): self.assertEqual(JLong(java.lang.Double(1.2345)), 1) def testFromFloat(self): self.assertEqual(JLong._canConvertToJava(1.2345), "explicit") @jpype.JImplements("java.util.function.LongSupplier") class q(object): @jpype.JOverride def getAsLong(self): return 4.5 # this will hit explicit conversion self.assertEqual(JObject(q()).getAsLong(), 4) def testFromLong(self): self.assertEqual(JLong(12345), 12345) self.assertEqual(JLong._canConvertToJava(12345), "implicit") def testFromObject(self): with self.assertRaises(TypeError): JLong(object()) with self.assertRaises(TypeError): JLong(JObject()) with self.assertRaises(TypeError): JLong(JString("A")) self.assertEqual(JLong._canConvertToJava(object()), "none") ja = JArray(JLong)(5) with self.assertRaises(TypeError): ja[1] = object() jf = JClass("jpype.common.Fixture") with self.assertRaises(TypeError): jf.static_long_field = object() with self.assertRaises(TypeError): jf().long_field = object() def testCallFloatFromNone(self): with self.assertRaises(TypeError): self.fixture.callFloat(None) with self.assertRaises(TypeError): self.fixture.static_long_field = None with self.assertRaises(TypeError): self.fixture.long_field = None def testThrow(self): # Check throw with self.assertRaises(JException): self.fixture.throwInt() with self.assertRaises(JException): self.cls.throwStaticInt() with self.assertRaises(JException): self.fixture.throwStaticInt() def checkType(self, q): # Check field self.fixture.long_field = q self.assertEqual(self.fixture.long_field, q) self.assertEqual(self.fixture.getLong(), q) # Check static field self.cls.static_long_field = q self.assertEqual(self.fixture.static_long_field, q) self.assertEqual(self.fixture.getStaticLong(), q) self.assertEqual(self.cls.getStaticLong(), q) # Check call self.assertEqual(self.fixture.callLong(q), q) self.assertEqual(self.cls.callStaticLong(q), q) def checkTypeFail(self, q, exc=TypeError): with self.assertRaises(exc): self.fixture.long_field = q with self.assertRaises(exc): self.fixture.callLong(q) with self.assertRaises(exc): self.fixture.callStaticLong(q) def testCastFloat(self): self.fixture.long_field = JLong(6.0) self.assertEqual(self.fixture.long_field, 6) def testCheckInt(self): self.checkType(1) def testCheckFloat(self): self.checkTypeFail(2.0) def testCheckRange(self): self.checkType(2**63 - 1) self.checkType(-2**63) self.checkTypeFail(2**63, exc=OverflowError) self.checkTypeFail(-2**63 - 1, exc=OverflowError) def testExplicitRange(self): # These will not overflow as they are explicit casts self.assertEqual(JLong(2**64), 0) self.assertEqual(JLong(-2**64), 0) def testCheckBool(self): self.checkType(True) self.checkType(False) def testCheckJBoolean(self): self.checkTypeFail(JBoolean(True)) self.checkTypeFail(JBoolean(False)) def testCheckJChar(self): self.checkType(JChar("A")) def testCheckJByte(self): self.checkType(JByte(-128)) self.checkType(JByte(127)) def testCheckJShort(self): self.checkType(JShort(-2**15)) self.checkType(JShort(2**15 - 1)) def testCheckJLong(self): self.checkType(JLong(-2**31 + 1)) self.checkType(JLong(2**31 - 1)) def testCheckJLong(self): self.checkType(JLong(-2**63 + 1)) self.checkType(JLong(2**63 - 1)) @common.requireNumpy def testCheckNumpyInt8(self): self.checkType(np.random.randint(-127, 128, dtype=np.int8)) self.checkType(np.random.randint(0, 255, dtype=np.uint8)) self.checkType(np.uint8(0)) self.checkType(np.uint8(255)) self.checkType(np.int8(-128)) self.checkType(np.int8(127)) @common.requireNumpy def testCheckNumpyInt16(self): self.checkType(np.random.randint(-2**15, 2**15 - 1, dtype=np.int16)) self.checkType(np.random.randint(0, 2**16 - 1, dtype=np.uint16)) self.checkType(np.uint16(0)) self.checkType(np.uint16(2**16 - 1)) self.checkType(np.int16(-2**15)) self.checkType(np.int16(2**15 - 1)) @common.requireNumpy def testCheckNumpyInt32(self): self.checkType(np.uint32(0)) self.checkType(np.uint32(2**32 - 1)) self.checkType(np.int32(-2**31)) self.checkType(np.int32(2**31 - 1)) @common.requireNumpy def testCheckNumpyInt64(self): #self.checkTypeFail(np.random.randint(-2**63,2**63-1, dtype=np.int64)) # FIXME OverflowError #self.checkType(np.uint64(np.random.randint(0,2**64-1, dtype=np.uint64))) # FIXME OverflowError # self.checkType(np.uint64(2**64-1)) self.checkType(np.int64(-2**63)) self.checkType(np.int64(2**63 - 1)) @common.requireNumpy def testCheckNumpyFloat32(self): self.checkTypeFail(np.float32(np.random.rand())) @common.requireNumpy def testCheckNumpyFloat64(self): self.checkTypeFail(np.float64(np.random.rand())) def checkArrayType(self, a, expected): # Check init ja = JArray(JLong)(a) self.assertElementsEqual(ja, expected) ja = JArray(JLong)(len(a)) ja[:] = a self.assertElementsEqual(ja, expected) return ja def checkArrayTypeFail(self, a): # Check init ja = JArray(JLong)(a) ja = JArray(JLong)(len(a)) ja[:] = a def testArrayConversion(self): a = [random.randint(-2**31, 2**31) for i in range(100)] jarr = self.checkArrayType(a, a) result = jarr[2:10] self.assertEqual(len(a[2:10]), len(result)) self.assertElementsAlmostEqual(a[2:10], result) # empty slice result = jarr[-1:3] expected = a[-1:3] self.assertElementsAlmostEqual(expected, result) result = jarr[3:-2] expected = a[3:-2] self.assertElementsAlmostEqual(expected, result) @common.requireNumpy def testArrayInitFromNPInt(self): a = np.random.randint(-2**31, 2**31 - 1, size=100, dtype=np.int) self.checkArrayType(a, a) @common.requireNumpy def testArrayInitFromNPInt8(self): a = np.random.randint(-2**7, 2**7 - 1, size=100, dtype=np.int8) self.checkArrayType(a, a) @common.requireNumpy def testArrayInitFromNPInt16(self): a = np.random.randint(-2**15, 2**15 - 1, size=100, dtype=np.int16) self.checkArrayType(a, a) @common.requireNumpy def testArrayInitFromNPInt32(self): a = np.random.randint(-2**31, 2**31 - 1, size=100, dtype=np.int32) self.checkArrayType(a, a) @common.requireNumpy def testArrayInitFromNPInt64(self): a = np.random.randint(-2**63, 2**63 - 1, size=100, dtype=np.int64) self.checkArrayType(a, a.astype(np.int64)) @common.requireNumpy def testArrayInitFromNPFloat32(self): a = np.random.random(100).astype(np.float32) self.checkArrayType(a, a.astype(np.int64)) @common.requireNumpy def testArrayInitFromNPFloat64(self): a = np.random.random(100).astype(np.float64) self.checkArrayType(a, a.astype(np.int64)) def testArraySetRange(self): ja = JArray(JLong)(3) ja[0:1] = [123] self.assertEqual(ja[0], 123) ja[0:1] = [-1] self.assertEqual(ja[0], -1) with self.assertRaises(TypeError): ja[0:1] = [1.000] with self.assertRaises(TypeError): ja[0:1] = [java.lang.Double(321)] with self.assertRaises(TypeError): ja[0:1] = [object()] def testArrayConversionFail(self): jarr = JArray(JLong)(VALUES) with self.assertRaises(TypeError): jarr[1] = 'a' def testArraySliceLength(self): jarr = JArray(JLong)(VALUES) jarr[1:2] = [1] with self.assertRaises(ValueError): jarr[1:2] = [1, 2, 3] def testArrayConversionInt(self): jarr = JArray(JLong)(VALUES) result = jarr[0: len(jarr)] self.assertElementsEqual(VALUES, result) result = jarr[2:10] self.assertElementsEqual(VALUES[2:10], result) def testArrayConversionError(self): jarr = JArray(JLong, 1)(10) with self.assertRaises(TypeError): jarr[1:2] = [dict()] # -1 is returned by python, if conversion fails also, ensure this works jarr[1:2] = [-1] def testArrayClone(self): array = JArray(JLong, 2)([[1, 2], [3, 4]]) carray = array.clone() # Verify the first dimension is cloned self.assertFalse(array.equals(carray)) # Copy is shallow self.assertTrue(array[0].equals(carray[0])) def testArrayGetSlice(self): contents = VALUES array = JArray(JLong)(contents) self.assertEqual(list(array[1:]), contents[1:]) self.assertEqual(list(array[:-1]), contents[:-1]) self.assertEqual(list(array[1:-1]), contents[1:-1]) def testArraySetSlice(self): contents = [1, 2, 3, 4] array = JArray(JLong)(contents) array[1:] = [5, 6, 7] contents[1:] = [5, 6, 7] self.assertEqual(list(array[:]), contents[:]) array[:-1] = [8, 9, 10] contents[:-1] = [8, 9, 10] self.assertEqual(list(array[:]), contents[:]) def testArrayGetSliceStep(self): contents = VALUES array = JArray(JLong)(contents) self.assertEqual(list(array[::2]), contents[::2]) self.assertEqual(list(array[::3]), contents[::3]) self.assertEqual(list(array[::4]), contents[::4]) self.assertEqual(list(array[::5]), contents[::5]) self.assertEqual(list(array[::6]), contents[::6]) self.assertEqual(list(array[::7]), contents[::7]) self.assertEqual(list(array[::8]), contents[::8]) self.assertEqual(list(array[1::3]), contents[1::3]) self.assertEqual(list(array[1:-2:3]), contents[1:-2:3]) def testArraySliceStepNeg(self): contents = VALUES array = JArray(JLong)(contents) self.assertEqual(list(array[::-1]), contents[::-1]) self.assertEqual(list(array[::-2]), contents[::-2]) self.assertEqual(list(array[::-3]), contents[::-3]) self.assertEqual(list(array[::-4]), contents[::-4]) self.assertEqual(list(array[::-5]), contents[::-5]) self.assertEqual(list(array[::-6]), contents[::-6]) self.assertEqual(list(array[2::-3]), contents[2::-3]) self.assertEqual(list(array[-2::-3]), contents[-2::-3]) def testArraySetArraySliceStep(self): contents = [1, 2, 3, 4, 5, 6] array = JArray(JLong)(contents) array[::2] = [5, 6, 7] contents[::2] = [5, 6, 7] self.assertEqual(list(array[:]), contents[:]) def testArrayEquals(self): contents = VALUES array = JArray(JLong)(contents) array2 = JArray(JLong)(contents) self.assertEqual(array, array) self.assertNotEqual(array, array2) def testArrayIter(self): contents = VALUES array = JArray(JLong)(contents) contents2 = [i for i in array] self.assertEqual(contents, contents2) def testArrayGetOutOfBounds(self): contents = [1, 2, 3, 4] array = JArray(JLong)(contents) with self.assertRaises(IndexError): array[5] self.assertEqual(array[-1], contents[-1]) self.assertEqual(array[-4], contents[-4]) with self.assertRaises(IndexError): array[-5] def testArraySetOutOfBounds(self): contents = [1, 2, 3, 4] array = JArray(JLong)(contents) with self.assertRaises(IndexError): array[5] = 1 array[-1] = 5 contents[-1] = 5 array[-4] = 6 contents[-4] = 6 self.assertEqual(list(array[:]), contents) with self.assertRaises(IndexError): array[-5] = 1 def testArraySliceCast(self): JA = JArray(JLong) ja = JA(VALUES) ja2 = ja[::2] jo = jpype.JObject(ja2, jpype.JObject) ja3 = jpype.JObject(jo, JA) self.assertEqual(type(jo), jpype.JClass("java.lang.Object")) self.assertEqual(type(ja2), JA) self.assertEqual(type(ja3), JA) self.assertEqual(list(ja2), list(ja3)) def testArrayReverse(self): n = list(VALUES) ja = JArray(JLong)(n) a = [i for i in reversed(ja)] n = [i for i in reversed(n)] self.assertEqual(a, n) def testArrayHash(self): ja = JArray(JLong)([1, 2, 3]) self.assertIsInstance(hash(ja), int) @common.requireNumpy def testArrayBufferDims(self): ja = JArray(JLong)(5) a = np.zeros((5, 2)) with self.assertRaisesRegex(TypeError, "incorrect"): ja[:] = a def testArrayBadItem(self): class q(object): def __int__(self): raise SystemError("nope") def __index__(self): raise SystemError("nope") ja = JArray(JLong)(5) a = [1, -1, q(), 3, 4] with self.assertRaisesRegex(SystemError, "nope"): ja[:] = a def testArrayBadDims(self): class q(bytes): # Lie about our length def __len__(self): return 5 a = q([1, 2, 3]) ja = JArray(JInt)(5) with self.assertRaisesRegex(ValueError, "Slice"): ja[:] = [1, 2, 3] with self.assertRaisesRegex(ValueError, "mismatch"): ja[:] = a jpype-1.3.0/test/jpypetest/test_jmethod.py000066400000000000000000000275361405671516700207440ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import sys import _jpype import jpype from jpype.types import * import common import types import functools import inspect # Code from stackoverflow # Reference http://stackoverflow.com/questions/13503079/how-to-create-a-copy-of-a-python-function def copy_func(f): """Based on http://stackoverflow.com/a/6528148/190597 (Glenn Maynard)""" g = types.FunctionType(f.__code__, f.__globals__, name=f.__name__, argdefs=f.__defaults__, closure=f.__closure__) g.__kwdefaults__ = f.__kwdefaults__ g = functools.update_wrapper(g, f) return g class JMethodTestCase(common.JPypeTestCase): """ Test for methods of JMethod (_jpype._JMethod) This should test how well the object matchs a Python3 function. * __self__: should appear on a bound, None otherwise. * __name__: should be set * __qualname__: should be set * __doc__: should be set * __annotations__: should give return type * __defaults__, __kwdefaults__, __code__, __globals__, __closure__: should be enough to "clone" the method. It should also be callable as a method, class method. Further inspect should work * inspect.getdoc() should match __doc__ * inspect.signature() should work * inspect.isroutine() should be True We are not going to try to pretend to be Python2. """ def setUp(self): common.JPypeTestCase.setUp(self) self.cls = jpype.JClass('java.lang.String') self.obj = self.cls('foo') def testMethodSelf(self): self.assertEqual(self.cls.substring.__self__, None) self.assertEqual(self.obj.substring.__self__, self.obj) def testMethodName(self): self.assertEqual(self.cls.substring.__name__, "substring") self.assertEqual(self.obj.substring.__name__, "substring") def testMethodQualName(self): self.assertEqual(self.cls.substring.__qualname__, "java.lang.String.substring") self.assertEqual(self.obj.substring.__qualname__, "java.lang.String.substring") def testMethodDoc(self): self.assertIsInstance(self.cls.substring.__doc__, str) self.assertIsInstance(self.obj.substring.__doc__, str) d = self.cls.substring.__doc__ self.cls.substring.__doc__ = None self.assertIsNone(self.cls.substring.__doc__) self.assertIsNone(self.obj.substring.__doc__) self.cls.substring.__doc__ = d def testMethodInspectDoc(self): self.assertIsInstance(inspect.getdoc(self.cls.substring), str) self.assertIsInstance(inspect.getdoc(self.obj.substring), str) self.assertIsInstance(inspect.getdoc(self.obj.format), str) def testMethodAnnotations(self): self.assertIsInstance(self.cls.substring.__annotations__, dict) self.assertIsNotNone(self.obj.substring.__annotations__) a = self.cls.substring.__annotations__ d = {} self.cls.substring.__annotations__ = d self.assertEqual(self.cls.substring.__annotations__, d) self.cls.substring.__annotations__ = a self.assertIsNotNone(self.cls.substring.__annotations__) # This one will need to change in Python 3.8 self.assertEqual(self.cls.substring.__annotations__[ "return"], self.cls) self.assertEqual(self.cls.trim.__annotations__[ "return"], self.cls) self.assertEqual(self.cls.getBytes.__annotations__, {}) def testMethodInspectSignature(self): self.assertIsInstance(inspect.signature( self.cls.substring), inspect.Signature) self.assertIsInstance(inspect.signature( self.obj.substring), inspect.Signature) self.assertEqual(inspect.signature( self.obj.substring).return_annotation, self.cls) def testMethodInspectFunction(self): self.assertTrue(inspect.isfunction(self.cls.substring)) self.assertTrue(inspect.isfunction(self.obj.substring)) def testMethodInspectRoutine(self): self.assertTrue(inspect.isroutine(self.cls.substring)) self.assertTrue(inspect.isroutine(self.obj.substring)) def testMethodClassCall(self): self.assertEqual(self.cls.substring(self.obj, 1), "oo") def testMethodClassCallWierd(self): self.assertEqual(self.cls.substring("foo", 1), "oo") def testMethodClassCallFail(self): with self.assertRaises(TypeError): self.cls.substring(1, 1) def testMethodCall(self): self.assertEqual(self.obj.substring(1), "oo") def testMethodClone(self): a = copy_func(self.cls.substring) self.assertEqual(a(self.obj, 1), "oo") a = copy_func(self.obj.substring) self.assertEqual(a(1), "oo") def testMethodDump(self): # This is replaced by doc, should be removed self.assertIsInstance(jpype.JString("foo").substring.dump(), str) def testMethodDump(self): # This is replaced by doc, should be removed (or do something useful) self.assertIsInstance(jpype.JString( "foo").substring.matchReport(), str) def testMethodHelp(self): import io import contextlib f = io.StringIO() with contextlib.redirect_stdout(f): help(jpype.JString("a").substring) s = f.getvalue() self.assertTrue("Java method dispatch" in s) self.assertTrue("substring(int)" in s) self.assertTrue("substring(int, int)" in s) @common.requireInstrumentation def testJMethod_get(self): fixture = JClass("jpype.common.Fixture")() _jpype.fault("PyJPMethod_get") with self.assertRaisesRegex(SystemError, "fault"): fixture.callInt(1) @common.requireInstrumentation def testJMethod_str(self): fixture = JClass("jpype.common.Fixture")() _jpype.fault("PyJPMethod_get") with self.assertRaisesRegex(SystemError, "fault"): str(fixture.callInt) @common.requireInstrumentation def testJMethod_str(self): Fixture = JClass("jpype.common.Fixture") fixture = Fixture() _jpype.fault("PyJPMethod_get") with self.assertRaisesRegex(SystemError, "fault"): repr(fixture.callInt) repr(Fixture.callInt) repr(fixture.callInt) @common.requireInstrumentation def testJMethod_selfFault(self): fixture = JClass("jpype.common.Fixture")() _jpype.fault("PyJPMethod_getSelf") with self.assertRaisesRegex(SystemError, "fault"): fixture.callInt.__self__ @common.requireInstrumentation def testJMethod_nameFault(self): fixture = JClass("jpype.common.Fixture")() _jpype.fault("PyJPMethod_getName") with self.assertRaisesRegex(SystemError, "fault"): fixture.callInt.__name__ @common.requireInstrumentation def testJMethod_qualnameFault(self): fixture = JClass("jpype.common.Fixture")() _jpype.fault("PyJPMethod_getQualName") with self.assertRaisesRegex(SystemError, "fault"): fixture.callInt.__qualname__ @common.requireInstrumentation def testJMethod_annotationsFault(self): fixture = JClass("jpype.common.Fixture")() _jpype.fault("PyJPMethod_getAnnotations") with self.assertRaisesRegex(SystemError, "fault"): fixture.callInt.__annotations__ @common.requireInstrumentation def testJMethod_docFault(self): fixture = JClass("jpype.common.Fixture")() _jpype.fault("PyJPMethod_getDoc") with self.assertRaisesRegex(SystemError, "fault"): fixture.callInt.__doc__ _jpype.fault("PyJPMethod_setDoc") with self.assertRaisesRegex(SystemError, "fault"): fixture.callInt.__doc__ = None @common.requireInstrumentation def testJMethod_docFault(self): fixture = JClass("jpype.common.Fixture")() _jpype.fault("PyJPMethod_getCodeAttr") with self.assertRaisesRegex(SystemError, "fault"): fixture.callFloat.__code__ @common.requireInstrumentation def testJMethod_beansFault(self): fixture = JClass("jpype.common.Fixture")() _jpype.fault("PyJPMethod_isBeanAccessor") with self.assertRaisesRegex(SystemError, "fault"): fixture.callInt._isBeanAccessor() _jpype.fault("PyJPMethod_isBeanMutator") with self.assertRaisesRegex(SystemError, "fault"): fixture.callInt._isBeanMutator() @common.requireInstrumentation def testJMethod_diagnosticsFault(self): fixture = JClass("jpype.common.Fixture")() _jpype.fault("PyJPMethod_matchReport") with self.assertRaisesRegex(SystemError, "fault"): fixture.callInt.matchReport() @common.requireInstrumentation def testJMethod_callFault(self): fixture = JClass("jpype.common.Fixture")() _jpype.fault("PyJPMethod_call") with self.assertRaisesRegex(SystemError, "fault"): fixture.callInt(1) def testJMethod_self(self): Fixture = JClass("jpype.common.Fixture") fixture = JClass("jpype.common.Fixture")() self.assertEqual(fixture.callInt.__self__, fixture) self.assertEqual(Fixture.callStaticInt.__self__, None) def testJMethod_name(self): fixture = JClass("jpype.common.Fixture")() self.assertIsInstance(fixture.callInt.__name__, str) self.assertEqual(fixture.callInt.__name__, 'callInt') def testJMethod_doc(self): fixture = JClass("jpype.common.Fixture")() self.assertIsInstance(fixture.callInt.__doc__, str) def testJMethod_annotations(self): fixture = JClass("jpype.common.Fixture")() self.assertIsInstance(fixture.callInt.__annotations__, dict) ann = fixture.callInt.__annotations__ expected = {'arg0': JInt, 'return': JInt} self.assertEqual(ann, expected) def testJMethod_closure(self): fixture = JClass("jpype.common.Fixture")() self.assertNotEqual(fixture.callInt.__closure__, None) def testJMethod_code(self): fixture = JClass("jpype.common.Fixture")() def f(): pass self.assertIsInstance(fixture.callInt.__code__, type(f.__code__)) def testJMethod_defaults(self): fixture = JClass("jpype.common.Fixture")() self.assertEqual(fixture.callInt.__defaults__, None) def testJMethod_kwdefaults(self): fixture = JClass("jpype.common.Fixture")() self.assertEqual(fixture.callInt.__kwdefaults__, None) def testJMethod_globals(self): fixture = JClass("jpype.common.Fixture")() self.assertIsInstance(fixture.callInt.__globals__, dict) def testJMethod_qualname(self): fixture = JClass("jpype.common.Fixture")() self.assertIsInstance(fixture.callInt.__qualname__, str) self.assertEqual(fixture.callInt.__qualname__, 'jpype.common.Fixture.callInt') def testMatches(self): js = JClass("java.lang.String")() self.assertFalse(js.substring._matches(object())) self.assertTrue(js.substring._matches(1)) self.assertTrue(js.substring._matches(1, 2)) self.assertFalse(js.substring._matches(1, 2, 3)) jpype-1.3.0/test/jpypetest/test_jobject.py000066400000000000000000000261611405671516700207230ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import _jpype import jpype import _jpype from jpype.types import * from jpype import java import common try: import numpy as np except ImportError: pass class JClassTestCase(common.JPypeTestCase): """ Test for methods of JObject Should test: - ``__getattribute__`` against methods, fields, python methods, and python properties - ``__setattr__`` against fields, final fields, python private fields - ``class_`` property - ``mro`` """ def setUp(self): common.JPypeTestCase.setUp(self) self.fixture = JClass('jpype.common.Fixture')() def testSetAttrPythonField(self): cls = JClass('java.lang.String') obj = cls('foo') # Setting a private field on a Java class is allowed obj._allowed = 1 with self.assertRaises(AttributeError): # Setting a public field on a Java class is forbidden obj.forbidden = 1 def testSetAttrFinal(self): cls = JClass('java.lang.Long') obj = cls(1) with self.assertRaises(AttributeError): # Setting a final field is forbidden obj.SIZE = 1 def testClass(self): obj = JClass('java.lang.Long') clsType = JClass('java.lang.Class') # Get class must return a java.lang.Class instance belonging to the class self.assertIsInstance(obj.class_, clsType) self.assertEqual(obj.class_.getSimpleName(), "Long") def testGetAttrProperty(self): obj = JClass('java.lang.RuntimeException')('oo') value = obj.args self.assertEqual(value, ('oo',)) def testSetAttrProperty(self): obj = JClass('java.lang.RuntimeException')('oo') with self.assertRaises(AttributeError): obj.args = 1 def testAttrStaticField(self): self.fixture.static_object_field = "fred" self.assertEqual(self.fixture.static_object_field, "fred") def testGetAttrField(self): v = self.fixture.object_field def testSetAttrField(self): self.fixture.object_field = "fred" def testGetAttrPrivateField(self): with self.assertRaises(AttributeError): v = self.fixture.private_object_field def testSetAttrPrivateField(self): with self.assertRaises(AttributeError): self.fixture.private_object_field = "fred" def testGetAttrFinalField(self): v = self.fixture.final_object_field def testSetAttrFinalField(self): with self.assertRaises(AttributeError): self.fixture.final_object_field = "fred" def testGetAttrStaticFinalField(self): self.assertEqual(self.fixture.final_static_object_field, "final static object field") def testSetAttrStaticFinalField(self): with self.assertRaises(AttributeError): self.fixture.finalStaticObjectField = "bar" def testStaticMethod(self): self.fixture.callStaticObject(JObject()) def testPrivateStaticMethod(self): with self.assertRaises(AttributeError): self.fixture.callPrivateStaticObject(JObject()) def testMethod(self): self.fixture.callObject(JObject()) def testPrivateMethod(self): with self.assertRaises(AttributeError): self.fixture.callPrivateObject(JObject()) def testProtectedMethod(self): with self.assertRaises(AttributeError): self.fixture.callProtectedObject(JObject()) def testObjectBoolTrue(self): self.fixture.object_field = True self.assertIsInstance(self.fixture.object_field, JClass('java.lang.Boolean')) self.assertEqual(str(self.fixture.object_field), str(True)) self.assertEqual(self.fixture.object_field, True) def testObjectBoolFalse(self): self.fixture.object_field = False self.assertIsInstance(self.fixture.object_field, JClass('java.lang.Boolean')) self.assertEqual(str(self.fixture.object_field), str(False)) self.assertEqual(self.fixture.object_field, False) def testObjectBoolJValue(self): self.fixture.object_field = JBoolean(True) self.assertIsInstance(self.fixture.object_field, JClass('java.lang.Boolean')) self.assertEqual(self.fixture.object_field, True) def testObjectShort(self): self.fixture.object_field = JShort(1) self.assertEqual(self.fixture.object_field, 1) self.assertIsInstance(self.fixture.object_field, JClass('java.lang.Short')) def testObjectInteger(self): self.fixture.object_field = JInt(2) self.assertEqual(self.fixture.object_field, 2) self.assertIsInstance(self.fixture.object_field, JClass('java.lang.Integer')) def testObjectLong(self): self.fixture.object_field = JLong(3) self.assertEqual(self.fixture.object_field, 3) self.assertIsInstance(self.fixture.object_field, JClass('java.lang.Long')) def testObjectFloat(self): self.fixture.object_field = JFloat(1.125) self.assertEqual(self.fixture.object_field, 1.125) self.assertIsInstance(self.fixture.object_field, JClass('java.lang.Float')) def testObjectDouble(self): self.fixture.object_field = JDouble(2.6125) self.assertEqual(self.fixture.object_field, 2.6125) self.assertIsInstance(self.fixture.object_field, JClass('java.lang.Double')) def testObjectField(self): with self.assertRaises(TypeError): self.fixture.object_field = object() with self.assertRaises(TypeError): self.fixture.static_object_field = object() def testArraySetRangeFail(self): ja = JArray(JObject)(4) with self.assertRaises(TypeError): ja[:] = [1, 2, object(), 3] ja[:] = [1, 2, 3, 4] @common.requireInstrumentation def testArraySetRangeFault(self): _jpype.fault("JPClass::setArrayRange") ja = JArray(JObject)(4) with self.assertRaisesRegex(SystemError, "fault"): ja[:] = [1, 2, 3, 4] def testAssignClass(self): self.fixture.object_field = JClass("java.lang.StringBuilder") self.assertIsInstance(self.fixture.object_field, jpype.java.lang.Class) self.assertEqual(self.fixture.object_field, JClass("java.lang.StringBuilder")) @common.requireInstrumentation def testSetFinalField(self): _jpype.fault("JPField::setStaticAttribute") with self.assertRaisesRegex(SystemError, "fault"): self.fixture.static_object_field = None def testHashNone(self): self.assertEqual(hash(JObject(None)), hash(None)) def testStrPrimitive(self): with self.assertRaisesRegex(TypeError, "requires a Java object"): _jpype._JObject.__str__(JInt(1)) def testGetAttrFail(self): jo = JClass("java.lang.Object")() with self.assertRaisesRegex(TypeError, "must be string"): getattr(jo, object()) def testSetAttrFail(self): jo = JClass("java.lang.Object")() with self.assertRaisesRegex(TypeError, "must be string"): setattr(jo, object(), 1) def testSetAttrFail2(self): fixture = JClass("jpype.common.Fixture")() with self.assertRaisesRegex(AttributeError, "is not settable"): setattr(fixture, "callObject", 4) def testJavaPrimitives(self): self.assertIsInstance( self.fixture.callObject(JByte(1)), java.lang.Byte) self.assertIsInstance( self.fixture.callObject(JShort(1)), java.lang.Short) self.assertIsInstance( self.fixture.callObject(JInt(1)), java.lang.Integer) self.assertIsInstance( self.fixture.callObject(JLong(1)), java.lang.Long) self.assertIsInstance( self.fixture.callObject(JFloat(1)), java.lang.Float) self.assertIsInstance(self.fixture.callObject( JDouble(1)), java.lang.Double) def testPythonPrimitives(self): self.assertIsInstance(self.fixture.callObject(1), java.lang.Long) self.assertIsInstance(self.fixture.callObject(1.0), java.lang.Double) @common.requireNumpy def testNumpyPrimitives(self): self.assertIsInstance( self.fixture.callObject(np.int8(1)), java.lang.Byte) self.assertIsInstance(self.fixture.callObject( np.int16(1)), java.lang.Short) self.assertIsInstance(self.fixture.callObject( np.int32(1)), java.lang.Integer) self.assertIsInstance(self.fixture.callObject( np.int64(1)), java.lang.Long) self.assertIsInstance(self.fixture.callObject( np.float32(1)), java.lang.Float) self.assertIsInstance(self.fixture.callObject( np.float64(1)), java.lang.Double) def testCompare(self): jo = JClass("java.lang.Object")() with self.assertRaises(TypeError): jo < 0 with self.assertRaises(TypeError): jo <= 0 with self.assertRaises(TypeError): jo > 0 with self.assertRaises(TypeError): jo >= 0 def testCompareNull(self): jo = JClass("java.lang.Object") jv = JObject(None, jo) self.assertEqual(jv, None) self.assertEqual(None, jv) self.assertNotEqual(JInt(1), jv) self.assertNotEqual(jv, JInt(1)) def testRepr(self): jo = JClass("java.lang.Object") jv = jo() jvn = JObject(None, jo) self.assertIsInstance(repr(jv), str) self.assertIsInstance(repr(jvn), str) self.assertEqual(repr(jv), "") self.assertEqual(repr(jvn), "") def testDeprecated(self): # this one should issue a warning jo = JClass("java.lang.Object") self.assertIsInstance(JObject(None, object), jo) def testGetSetBad(self): JS = JClass("java.lang.String") js = JS() with self.assertRaises(TypeError): JS.__getattribute__(js, object()) with self.assertRaises(TypeError): setattr(js, object(), 1) def testGetSetBad(self): jo = JClass("java.lang.Object")() self.assertTrue(jo != JInt(0)) self.assertFalse(jo == JInt(0)) self.assertTrue(JInt(0) != jo) self.assertFalse(JInt(0) == jo) jpype-1.3.0/test/jpypetest/test_jpackage.py000066400000000000000000000044711405671516700210500ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import _jpype import jpype from jpype.types import * from jpype import JPackage import common class JPackageTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) self.jl = JPackage('java.lang') def testCreate(self): self.assertEqual(self.jl.String, JClass('java.lang.String')) def testFail0(self): with self.assertRaises(TypeError): JPackage(1) # def testFail1(self): # #with self.assertRaises(RuntimeError): # jl = JPackage('java.nosuch') def testFail2(self): with self.assertRaises(AttributeError): self.jl.NoSuch def testFail3(self): with self.assertRaises(AttributeError): self.jl.bar def testStr(self): self.assertIsInstance(str(self.jl), str) self.assertEqual(str(self.jl), "java.lang") def testRepr(self): self.assertIsInstance(repr(self.jl), str) self.assertEqual(repr(self.jl), "") def testCall(self): with self.assertRaises(TypeError): self.jl() def testDir(self): self.assertIsInstance(dir(self.jl), list) def testGetAttr(self): with self.assertRaises(TypeError): self.jl.__getattribute__(object()) def testSetAttr(self): with self.assertRaises(TypeError): self.jl.__setattr__(object(), 1) def testInvalid(self): JL = JPackage("java.lng") with self.assertRaisesRegex(AttributeError, "Java package 'java.lng' is not valid"): getattr(JL, "foo") jpype-1.3.0/test/jpypetest/test_jshort.py000066400000000000000000000462631405671516700206210ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import sys import jpype import common import random import _jpype import jpype from jpype import java from jpype.types import * try: import numpy as np except ImportError: pass VALUES = [random.randint(-2**15, 2**15 - 1) for i in range(10)] class JShortTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) self.cls = JClass("jpype.common.Fixture") self.fixture = self.cls() @common.requireInstrumentation def testJPNumberLong_int(self): jd = JShort(1) _jpype.fault("PyJPNumberLong_int") with self.assertRaisesRegex(SystemError, "fault"): int(jd) _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): int(jd) int(jd) @common.requireInstrumentation def testJPNumberLong_float(self): jd = JShort(1) _jpype.fault("PyJPNumberLong_float") with self.assertRaisesRegex(SystemError, "fault"): float(jd) _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): float(jd) float(jd) @common.requireInstrumentation def testJPNumberLong_str(self): jd = JShort(1) _jpype.fault("PyJPNumberLong_str") with self.assertRaisesRegex(SystemError, "fault"): str(jd) _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): str(jd) str(jd) @common.requireInstrumentation def testJPNumberLong_repr(self): jd = JShort(1) _jpype.fault("PyJPNumberLong_repr") with self.assertRaisesRegex(SystemError, "fault"): repr(jd) _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): repr(jd) repr(jd) @common.requireInstrumentation def testJPNumberLong_compare(self): jd = JShort(1) _jpype.fault("PyJPNumberLong_compare") with self.assertRaisesRegex(SystemError, "fault"): jd == 1 _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): jd == 1 jd == 1 @common.requireInstrumentation def testJPNumberLong_hash(self): jd = JShort(1) _jpype.fault("PyJPNumberLong_hash") with self.assertRaises(SystemError): hash(jd) _jpype.fault("PyJPModule_getContext") with self.assertRaises(SystemError): hash(jd) hash(jd) @common.requireInstrumentation def testFault(self): _jpype.fault("JPShortType::findJavaConversion") with self.assertRaises(SystemError): JShort(1.0) @common.requireInstrumentation def testConversionFault(self): _jpype.fault("JPShortType::findJavaConversion") with self.assertRaisesRegex(SystemError, "fault"): JShort._canConvertToJava(object()) @common.requireInstrumentation def testArrayFault(self): ja = JArray(JShort)(5) _jpype.fault("JPJavaFrame::NewShortArray") with self.assertRaisesRegex(SystemError, "fault"): JArray(JShort)(1) _jpype.fault("JPJavaFrame::SetShortArrayRegion") with self.assertRaisesRegex(SystemError, "fault"): ja[0] = 0 _jpype.fault("JPJavaFrame::GetShortArrayRegion") with self.assertRaisesRegex(SystemError, "fault"): print(ja[0]) _jpype.fault("JPJavaFrame::GetShortArrayElements") # Special case, only BufferError is allowed from getBuffer with self.assertRaises(BufferError): memoryview(ja[0:3]) _jpype.fault("JPJavaFrame::ReleaseShortArrayElements") with self.assertRaisesRegex(SystemError, "fault"): ja[0:3] = bytes([1, 2, 3]) _jpype.fault("JPJavaFrame::ReleaseShortArrayElements") with self.assertRaisesRegex(SystemError, "fault"): jpype.JObject(ja[::2], jpype.JObject) _jpype.fault("JPJavaFrame::ReleaseShortArrayElements") def f(): # Special case no fault is allowed memoryview(ja[0:3]) f() _jpype.fault("JPShortType::setArrayRange") with self.assertRaisesRegex(SystemError, "fault"): ja[1:3] = [0, 0] def testFromJShortWiden(self): self.assertEqual(JShort(JByte(123)), 123) self.assertEqual(JShort(JShort(12345)), 12345) self.assertEqual(JShort(JInt(12345678)), JShort(12345678)) self.assertEqual(JShort(JLong(12345678)), JShort(12345678)) def testFromNone(self): with self.assertRaises(TypeError): JShort(None) self.assertEqual(JShort._canConvertToJava(None), "none") def testUnBox(self): self.assertEqual(JShort(java.lang.Double(1.2345)), 1) def testFromFloat(self): self.assertEqual(JShort._canConvertToJava(1.2345), "explicit") def testFromLong(self): self.assertEqual(JShort(12345), 12345) self.assertEqual(JShort._canConvertToJava(12345), "implicit") def testFromObject(self): with self.assertRaises(TypeError): JShort(object()) with self.assertRaises(TypeError): JShort(JObject()) with self.assertRaises(TypeError): JShort(JString("A")) self.assertEqual(JShort._canConvertToJava(object()), "none") ja = JArray(JShort)(5) with self.assertRaises(TypeError): ja[1] = object() jf = JClass("jpype.common.Fixture") with self.assertRaises(TypeError): jf.static_short_field = object() with self.assertRaises(TypeError): jf().short_field = object() def testCallFloatFromNone(self): with self.assertRaises(TypeError): self.fixture.callShort(None) with self.assertRaises(TypeError): self.fixture.static_short_field = None with self.assertRaises(TypeError): self.fixture.short_field = None def testThrow(self): # Check throw with self.assertRaises(JException): self.fixture.throwFloat() with self.assertRaises(JException): self.cls.throwStaticFloat() with self.assertRaises(JException): self.fixture.throwStaticFloat() def checkType(self, q): # Check field self.fixture.short_field = q self.assertEqual(self.fixture.short_field, q) self.assertEqual(self.fixture.getShort(), q) # Check static field self.cls.static_short_field = q self.assertEqual(self.fixture.static_short_field, q) self.assertEqual(self.fixture.getStaticShort(), q) self.assertEqual(self.cls.getStaticShort(), q) # Check call self.assertEqual(self.fixture.callShort(q), q) self.assertEqual(self.cls.callStaticShort(q), q) def checkTypeFail(self, q, exc=TypeError): with self.assertRaises(exc): self.fixture.short_field = q with self.assertRaises(exc): self.fixture.callShort(q) with self.assertRaises(exc): self.fixture.callStaticShort(q) def testCastFloat(self): self.fixture.short_field = JShort(6.0) self.assertEqual(self.fixture.short_field, 6) def testCheckInt(self): self.checkType(1) def testCheckFloat(self): self.checkTypeFail(2.0) def testCheckRange(self): self.checkType(2**15 - 1) self.checkType(-2**15) self.checkTypeFail(2**15, exc=OverflowError) self.checkTypeFail(-2**15 - 1, exc=OverflowError) def testExplicitRange(self): # These will not overflow as they are explicit casts self.assertEqual(JShort(2**16), 0) self.assertEqual(JShort(-2**16), 0) def testCheckBool(self): self.checkType(True) self.checkType(False) def testCheckJBoolean(self): self.checkTypeFail(JBoolean(True)) self.checkTypeFail(JBoolean(False)) def testCheckJChar(self): self.checkType(JChar("A")) def testCheckJByte(self): self.checkType(JByte(-128)) self.checkType(JByte(127)) def testCheckJShort(self): self.checkType(JShort(-2**15)) self.checkType(JShort(2**15 - 1)) def testCheckJInt(self): self.checkTypeFail(JInt(-2**31 + 1)) self.checkTypeFail(JInt(2**31 - 1)) def testCheckJLong(self): self.checkTypeFail(JLong(-2**63 + 1)) self.checkTypeFail(JLong(2**63 - 1)) @common.requireNumpy def testCheckNumpyInt8(self): self.checkType(np.random.randint(-127, 128, dtype=np.int8)) self.checkType(np.random.randint(0, 255, dtype=np.uint8)) self.checkType(np.uint8(0)) self.checkType(np.uint8(255)) self.checkType(np.int8(-128)) self.checkType(np.int8(127)) @common.requireNumpy def testCheckNumpyInt16(self): self.checkType(np.random.randint(-2**15, 2**15 - 1, dtype=np.int16)) self.checkType(np.uint16(0)) self.checkTypeFail(np.uint16(2**16 - 1), exc=OverflowError) self.checkType(np.int16(-2**15)) self.checkType(np.int16(2**15 - 1)) @common.requireNumpy def testCheckNumpyInt32(self): self.checkType(np.uint32(0)) self.checkTypeFail(np.uint32(2**32 - 1), exc=OverflowError) self.checkTypeFail(np.int32(-2**31), exc=OverflowError) self.checkTypeFail(np.int32(2**31 - 1), exc=OverflowError) @common.requireNumpy def testCheckNumpyInt64(self): #self.checkTypeFail(np.random.randint(-2**63,2**63-1, dtype=np.int64)) # FIXME OverflowError #self.checkType(np.uint64(np.random.randint(0,2**64-1, dtype=np.uint64))) # FIXME OverflowError # self.checkType(np.uint64(2**64-1)) self.checkTypeFail(np.int64(-2**63), exc=OverflowError) self.checkTypeFail(np.int64(2**63 - 1), exc=OverflowError) @common.requireNumpy def testCheckNumpyFloat32(self): self.checkTypeFail(np.float32(np.random.rand())) @common.requireNumpy def testCheckNumpyFloat64(self): self.checkTypeFail(np.float64(np.random.rand())) def checkArrayType(self, a, expected): # Check init ja = JArray(JShort)(a) self.assertElementsEqual(ja, expected) ja = JArray(JShort)(len(a)) ja[:] = a self.assertElementsEqual(ja, expected) return ja def checkArrayTypeFail(self, a): # Check init ja = JArray(JShort)(a) ja = JArray(JShort)(len(a)) ja[:] = a def testArrayConversion(self): a = [random.randint(-2**15, 2**15 - 1) for i in range(100)] jarr = self.checkArrayType(a, a) result = jarr[2:10] self.assertEqual(len(a[2:10]), len(result)) self.assertElementsAlmostEqual(a[2:10], result) # empty slice result = jarr[-1:3] expected = a[-1:3] self.assertElementsAlmostEqual(expected, result) result = jarr[3:-2] expected = a[3:-2] self.assertElementsAlmostEqual(expected, result) @common.requireNumpy def testArrayInitFromNPInt(self): a = np.random.randint(-2**31, 2**31 - 1, size=100, dtype=np.int) self.checkArrayType(a, a.astype(np.int16)) @common.requireNumpy def testArrayInitFromNPInt8(self): a = np.random.randint(-2**7, 2**7 - 1, size=100, dtype=np.int8) self.checkArrayType(a, a) @common.requireNumpy def testArrayInitFromNPInt16(self): a = np.random.randint(-2**15, 2**15 - 1, size=100, dtype=np.int16) self.checkArrayType(a, a) @common.requireNumpy def testArrayInitFromNPInt32(self): a = np.random.randint(-2**31, 2**31 - 1, size=100, dtype=np.int32) self.checkArrayType(a, a.astype(np.int16)) @common.requireNumpy def testArrayInitFromNPInt64(self): a = np.random.randint(-2**63, 2**63 - 1, size=100, dtype=np.int64) self.checkArrayType(a, a.astype(np.int16)) @common.requireNumpy def testArrayInitFromNPFloat32(self): a = np.random.random(100).astype(np.float32) self.checkArrayType(a, a.astype(np.int16)) @common.requireNumpy def testArrayInitFromNPFloat64(self): a = np.random.random(100).astype(np.float64) self.checkArrayType(a, a.astype(np.int16)) def testArraySetRange(self): ja = JArray(JShort)(3) ja[0:1] = [123] self.assertEqual(ja[0], 123) ja[0:1] = [-1] self.assertEqual(ja[0], -1) with self.assertRaises(TypeError): ja[0:1] = [1.000] with self.assertRaises(TypeError): ja[0:1] = [java.lang.Double(321)] with self.assertRaises(TypeError): ja[0:1] = [object()] def testArrayConversionFail(self): jarr = JArray(JShort)(VALUES) with self.assertRaises(TypeError): jarr[1] = 'a' def testArraySliceLength(self): jarr = JArray(JShort)(VALUES) jarr[1:2] = [1] with self.assertRaises(ValueError): jarr[1:2] = [1, 2, 3] def testArrayConversionInt(self): jarr = JArray(JShort)(VALUES) result = jarr[0: len(jarr)] self.assertElementsEqual(VALUES, result) result = jarr[2:10] self.assertElementsEqual(VALUES[2:10], result) def testArrayConversionError(self): jarr = JArray(JShort, 1)(10) with self.assertRaises(TypeError): jarr[1:2] = [dict()] # -1 is returned by python, if conversion fails also, ensure this works jarr[1:2] = [-1] def testArrayClone(self): array = JArray(JShort, 2)([[1, 2], [3, 4]]) carray = array.clone() # Verify the first dimension is cloned self.assertFalse(array.equals(carray)) # Copy is shallow self.assertTrue(array[0].equals(carray[0])) def testArrayGetSlice(self): contents = VALUES array = JArray(JShort)(contents) self.assertEqual(list(array[1:]), contents[1:]) self.assertEqual(list(array[:-1]), contents[:-1]) self.assertEqual(list(array[1:-1]), contents[1:-1]) def testArraySetSlice(self): contents = [1, 2, 3, 4] array = JArray(JShort)(contents) array[1:] = [5, 6, 7] contents[1:] = [5, 6, 7] self.assertEqual(list(array[:]), contents[:]) array[:-1] = [8, 9, 10] contents[:-1] = [8, 9, 10] self.assertEqual(list(array[:]), contents[:]) def testArrayGetSliceStep(self): contents = VALUES array = JArray(JShort)(contents) self.assertEqual(list(array[::2]), contents[::2]) self.assertEqual(list(array[::3]), contents[::3]) self.assertEqual(list(array[::4]), contents[::4]) self.assertEqual(list(array[::5]), contents[::5]) self.assertEqual(list(array[::6]), contents[::6]) self.assertEqual(list(array[::7]), contents[::7]) self.assertEqual(list(array[::8]), contents[::8]) self.assertEqual(list(array[1::3]), contents[1::3]) self.assertEqual(list(array[1:-2:3]), contents[1:-2:3]) def testArraySliceStepNeg(self): contents = VALUES array = JArray(JShort)(contents) self.assertEqual(list(array[::-1]), contents[::-1]) self.assertEqual(list(array[::-2]), contents[::-2]) self.assertEqual(list(array[::-3]), contents[::-3]) self.assertEqual(list(array[::-4]), contents[::-4]) self.assertEqual(list(array[::-5]), contents[::-5]) self.assertEqual(list(array[::-6]), contents[::-6]) self.assertEqual(list(array[2::-3]), contents[2::-3]) self.assertEqual(list(array[-2::-3]), contents[-2::-3]) def testArraySetArraySliceStep(self): contents = [1, 2, 3, 4, 5, 6] array = JArray(JShort)(contents) array[::2] = [5, 6, 7] contents[::2] = [5, 6, 7] self.assertEqual(list(array[:]), contents[:]) def testArrayEquals(self): contents = VALUES array = JArray(JShort)(contents) array2 = JArray(JShort)(contents) self.assertEqual(array, array) self.assertNotEqual(array, array2) def testArrayIter(self): contents = VALUES array = JArray(JShort)(contents) contents2 = [i for i in array] self.assertEqual(contents, contents2) def testArrayGetOutOfBounds(self): contents = [1, 2, 3, 4] array = JArray(JShort)(contents) with self.assertRaises(IndexError): array[5] self.assertEqual(array[-1], contents[-1]) self.assertEqual(array[-4], contents[-4]) with self.assertRaises(IndexError): array[-5] def testArraySetOutOfBounds(self): contents = [1, 2, 3, 4] array = JArray(JShort)(contents) with self.assertRaises(IndexError): array[5] = 1 array[-1] = 5 contents[-1] = 5 array[-4] = 6 contents[-4] = 6 self.assertEqual(list(array[:]), contents) with self.assertRaises(IndexError): array[-5] = 1 def testArraySliceCast(self): JA = JArray(JShort) ja = JA(VALUES) ja2 = ja[::2] jo = jpype.JObject(ja2, jpype.JObject) ja3 = jpype.JObject(jo, JA) self.assertEqual(type(jo), jpype.JClass("java.lang.Object")) self.assertEqual(type(ja2), JA) self.assertEqual(type(ja3), JA) self.assertEqual(list(ja2), list(ja3)) def testArrayReverse(self): n = list(VALUES) ja = JArray(JShort)(n) a = [i for i in reversed(ja)] n = [i for i in reversed(n)] self.assertEqual(a, n) def testArrayHash(self): ja = JArray(JShort)([1, 2, 3]) self.assertIsInstance(hash(ja), int) @common.requireNumpy def testArrayBufferDims(self): ja = JArray(JShort)(5) a = np.zeros((5, 2)) with self.assertRaisesRegex(TypeError, "incorrect"): ja[:] = a def testArrayBadItem(self): class q(object): def __int__(self): raise SystemError("nope") def __index__(self): raise SystemError("nope") ja = JArray(JShort)(5) a = [1, 2, q(), 3, 4] with self.assertRaisesRegex(SystemError, "nope"): ja[:] = a def testArrayBadDims(self): class q(bytes): # Lie about our length def __len__(self): return 5 a = q([1, 2, 3]) ja = JArray(JShort)(5) with self.assertRaisesRegex(ValueError, "Slice"): ja[:] = [1, 2, 3] with self.assertRaisesRegex(ValueError, "mismatch"): ja[:] = a jpype-1.3.0/test/jpypetest/test_jstring.py000066400000000000000000000123621405671516700207610ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import _jpype import jpype from jpype.types import * import common class JStringTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) def testAddself(self): a = jpype.JString("abc") a = a + "def" self.assertEqual(a, "abcdef") def testEq(self): a = jpype.JString("abc") b = jpype.JClass("java.lang.String")("abc") self.assertEqual(a, b) def testEqPy(self): a = jpype.JString("abc") self.assertEqual(a, "abc") def testNotEq(self): a = jpype.JString("abc") b = jpype.JClass("java.lang.String")("def") self.assertNotEqual(a, b) def testNotEqPy(self): a = jpype.JString("abc") self.assertNotEqual(a, "def") def testLen(self): a = jpype.JString("abc") self.assertEqual(len(a), 3) def testGetItem(self): a = jpype.JString("abc") self.assertEqual(a[0], 'a') self.assertEqual(a[1], 'b') self.assertEqual(a[2], 'c') self.assertEqual(a[-1], 'c') self.assertEqual(a[-2], 'b') self.assertEqual(a[-3], 'a') with self.assertRaises(IndexError): x = a[3] with self.assertRaises(IndexError): x = a[-4] def testLt(self): a = jpype.JString("abc") b = jpype.JString("def") self.assertTrue(a < b) self.assertFalse(b < a) self.assertFalse(b < "def") self.assertTrue(a < "def") def testLe(self): a = jpype.JString("abc") b = jpype.JString("def") self.assertTrue(a <= a) self.assertTrue(a <= b) self.assertFalse(b <= a) self.assertTrue(b <= "def") self.assertTrue(a <= "def") def testGt(self): a = jpype.JString("abc") b = jpype.JString("def") self.assertFalse(a < a) self.assertTrue(a < b) self.assertFalse(b < a) self.assertFalse(b < "def") self.assertTrue(a < "def") def testGe(self): a = jpype.JString("abc") b = jpype.JString("def") self.assertTrue(a >= a) self.assertFalse(a >= b) self.assertTrue(b >= a) self.assertTrue(b >= "def") self.assertFalse(a >= "def") def testContains(self): a = jpype.JString("abc") self.assertTrue("ab" in a) self.assertFalse("cd" in a) def testHash(self): a = jpype.JString("abc") self.assertEqual(hash(a), hash("abc")) def testRepr(self): a = jpype.JString("abc") self.assertEqual(repr(a), "'abc'") def testConversion(self): self.assertEqual(jpype.JString("AAAA"), "AAAA") self.assertEqual(jpype.JString(bytes([65, 65, 65, 65])), "AAAA") def testStringDictKey1(self): d = dict() d['foo'] = 'a' self.assertEqual(d[JString('foo')], 'a') def testStringDictKey2(self): d = dict() d[JString('foo')] = 'a' self.assertEqual(d['foo'], 'a') def testStringDictKey3(self): d = dict() d[JString('foo')] = 'a' self.assertEqual(d[JString('foo')], 'a') def testNullString(self): self.assertEqual(str(JObject(None, JString)), "null") def testNullCompare(self): jsn = JObject(None, JString) self.assertFalse("a" == jsn) self.assertTrue("a" != jsn) self.assertFalse(jsn == "a") self.assertTrue(jsn != "a") self.assertTrue(jsn == jsn) self.assertFalse(jsn != jsn) with self.assertRaises(ValueError): jsn < "a" with self.assertRaises(ValueError): jsn <= "a" with self.assertRaises(ValueError): jsn > "a" with self.assertRaises(ValueError): jsn >= "a" with self.assertRaises(ValueError): "a" < jsn with self.assertRaises(ValueError): "a" <= jsn with self.assertRaises(ValueError): "a" > jsn with self.assertRaises(ValueError): "a" >= jsn def testNullAdd(self): jsn = JObject(None, JString) with self.assertRaises(ValueError): jsn + "a" def testNullHash(self): jsn = JObject(None, JString) self.assertEqual(hash(jsn), hash(None)) def testSlice(self): s = 'abcdefghijklmnop' s2 = JString(s) self.assertEqual(s[:], s2[:]) self.assertEqual(s[1:5], s2[1:5]) self.assertEqual(s[:5], s2[:5]) self.assertEqual(s[3:], s2[3:]) self.assertEqual(s[::-1], s2[::-1]) jpype-1.3.0/test/jpypetest/test_jvmfinder.py000066400000000000000000000175301405671516700212670ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** # part of JPype1; author Martin K. Scherer; 2014 import unittest from unittest import mock import common import os import jpype._jvmfinder from jpype._jvmfinder import * class JVMFinderTest(unittest.TestCase): """ test some methods to obtain a jvm. TODO: add windows (need to mock registry) """ def test_find_libjvm(self): """ test JVMFinder.find_libjvm does not return broken jvm implementation. """ walk_fake = [('jre', ('lib',), ()), ('jre/lib', ('amd64',), ()), ('jre/lib/amd64', ('cacao', 'jamvm', 'server'), ()), ('jre/lib/amd64/cacao', ('',), ('libjvm.so',)), ('jre/lib/amd64/jamvm', ('',), ('libjvm.so',)), ('jre/lib/amd64/server', ('',), ('libjvm.so',)), ] with mock.patch('os.walk') as mockwalk: # contains broken and working jvms mockwalk.return_value = walk_fake finder = jpype._jvmfinder.LinuxJVMFinder() p = finder.find_libjvm('arbitrary java home') self.assertEqual( p, os.path.join('jre/lib/amd64/server', 'libjvm.so'), 'wrong jvm returned') with mock.patch('os.walk') as mockwalk: # contains only broken jvms, since server impl is removed walk_fake[-1] = ((), (), (),) mockwalk.return_value = walk_fake finder = jpype._jvmfinder.LinuxJVMFinder() with self.assertRaises(JVMNotSupportedException) as context: finder.find_libjvm('arbitrary java home') @mock.patch('os.walk') @mock.patch('os.path.exists') @mock.patch('os.path.realpath') def test_get_from_bin(self, mock_real_path, mock_path_exists, mock_os_walk): """ test _get_from_bin method (used in linux and darwin) '/usr/bin/java' => some jre/jdk path """ java_path = '/usr/lib/jvm/java-6-openjdk-amd64/bin/java' mock_os_walk.return_value = [ ('/usr/lib/jvm/java-6-openjdk-amd64/jre/lib/amd64/server', ('',), ('libjvm.so',))] mock_path_exists.return_value = True mock_real_path.return_value = '/usr/lib/jvm/java-6-openjdk-amd64/bin/java' finder = jpype._jvmfinder.LinuxJVMFinder() p = finder._get_from_bin() self.assertEqual( p, os.path.join('/usr/lib/jvm/java-6-openjdk-amd64/jre/lib/amd64/server', 'libjvm.so')) @mock.patch('platform.mac_ver') def testDarwinBinary(self, mock_mac_ver): # this version has java_home binary mock_mac_ver.return_value = ('10.6.8', '', '') expected = '/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home\n' finder = jpype._jvmfinder.DarwinJVMFinder() # fake check_output with mock.patch('subprocess.check_output') as mock_checkoutput: mock_checkoutput.return_value = expected p = finder._javahome_binary() self.assertEqual(p, expected.strip()) # this version has no java_home binary mock_mac_ver.return_value = ('10.5', '', '') p = finder._javahome_binary() self.assertEqual(p, None) # FIXME this is testing the details of the implementation rather than the results. # it is included only for coverage purposes. Revise this to be a more meaningful test # next time it breaks. # FIXME this test does passes locally but not in the CI. Disabling for now. @common.unittest.skip def testPlatform(self): with mock.patch('jpype._jvmfinder.sys') as mocksys, mock.patch('jpype._jvmfinder.WindowsJVMFinder') as finder: mocksys.platform = 'win32' jpype._jvmfinder.getDefaultJVMPath() self.assertIn(finder().get_jvm_path, finder.mock_calls) with mock.patch('jpype._jvmfinder.sys') as mocksys, mock.patch('jpype._jvmfinder.LinuxJVMFinder') as finder: mocksys.platform = 'linux' getDefaultJVMPath() self.assertIn(finder().get_jvm_path, finder.mock_calls) with mock.patch('jpype._jvmfinder.sys') as mocksys, mock.patch('jpype._jvmfinder.DarwinJVMFinder') as finder: mocksys.platform = 'darwin' getDefaultJVMPath() self.assertIn(finder().get_jvm_path, finder.mock_calls) def testLinuxGetFromBin(self): finder = jpype._jvmfinder.LinuxJVMFinder() def f(s): return s with mock.patch('os.path') as pathmock, \ mock.patch('jpype._jvmfinder.JVMFinder.find_libjvm') as mockfind: pathmock.exists.return_value = True pathmock.realpath = f pathmock.abspath = f pathmock.dirname = os.path.dirname pathmock.join = os.path.join finder._get_from_bin() self.assertEqual( pathmock.dirname.mock_calls[0][1], (finder._java,)) # FIXME this test is faking files using the mock system. Replace it with stub # files so that we have a more accurate test rather than just testing the implementation. # FIXME this fails in the CI but works locally. Disabling this for now. @common.unittest.skip def testCheckArch(self): import struct with mock.patch("builtins.open", mock.mock_open(read_data="data")) as mock_file, \ self.assertRaises(JVMNotSupportedException): jpype._jvmfinder._checkJVMArch('path', 2**32) data = struct.pack(' 3: return False print() for i in range(len(grow0)): print(' Pass%d: %f %f - %d %d %d' % (i, grow0[i], grow1[i], rss_memory[i], jvm_total_mem[i], jvm_free_mem[i])) print() return True @subrun.TestCase(individual=True) class LeakTestCase(unittest.TestCase): def setUp(self): root = path.dirname(path.abspath(path.dirname(__file__))) jpype.addClassPath(path.join(root, 'classes')) jvm_path = jpype.getDefaultJVMPath() classpath_arg = "-Djava.class.path=%s" classpath_arg %= jpype.getClassPath() jpype.startJVM(jvm_path, "-ea", # "-Xcheck:jni", "-Xmx256M", "-Xms16M", classpath_arg) def assertNotLeaky(self, function, counts=5000): lc = LeakChecker() assert not lc.memTest(function, counts), 'Potential leak found' @unittest.skipUnless(haveResource(), "resource not available") def testStringLeak(self): def stringFunc(): jpype.java.lang.String('aaaaaaaaaaaaaaaaa') self.assertNotLeaky(stringFunc) @unittest.skipUnless(haveResource(), "resource not available") def testStringLeak__str__(self): def stringFunc(): # Casting to a string includes a cache stage, we want to make sure # that the cache is tidying up properly. s = jpype.types.JString('aaaaaaaaaaaaaaaaa') str(s) self.assertNotLeaky(stringFunc) @unittest.skipUnless(haveResource(), "resource not available") def testClassLeak(self): def classFunc(): cls = jpype.JClass('java.lang.String') self.assertNotLeaky(classFunc) @unittest.skipUnless(haveResource(), "resource not available") def testCtorLeak(self): cls = jpype.JClass("java.lang.String") def func(): cls("test") self.assertNotLeaky(func) @unittest.skipUnless(haveResource(), "resource not available") def testInvokeLeak(self): jstr = jpype.JString("aaaaaaaaaaaaaaaaaaaaaaaaaaaaa") def func(): jstr.getBytes() self.assertNotLeaky(func) jpype-1.3.0/test/jpypetest/test_leak2.py000066400000000000000000000053411405671516700202760ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # *****************************************************************************import _jpype import jpype from jpype.types import * import sys import logging import time import common class Tracer(object): ctor = 0 dtor = 0 def __init__(self): Tracer.ctor += 1 def __del__(self): Tracer.dtor += 1 @staticmethod def reset(): Tracer.ctor = 0 Tracer.dtor = 0 @staticmethod def leaked(): return Tracer.ctor - Tracer.dtor @staticmethod def attach(obj): setattr(obj, "_trace", Tracer()) # This test finds reference counting leak by attaching an # object that lives as long as the wrapper is alive. # It can't detect Java reference counter leaks. class Leak2TestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) self.fixture = JClass('jpype.common.Fixture')() Tracer.reset() def testArrayCall(self): JA = JArray(JInt) def call(): inst = JA(100) Tracer.attach(inst) self.fixture.callObject(inst) for i in range(100): call() self.assertEqual(Tracer.leaked(), 0) def testArrayMemoryView(self): JA = JArray(JInt) def call(): inst = JA(100) Tracer.attach(inst) memoryview(inst) for i in range(100): call() self.assertEqual(Tracer.leaked(), 0) def testBufferCall(self): byte_buffer = jpype.JClass('java.nio.ByteBuffer') def call(): inst = byte_buffer.allocateDirect(10) Tracer.attach(inst) self.fixture.callObject(inst) for i in range(100): call() self.assertEqual(Tracer.leaked(), 0) def testBufferMemoryView(self): byte_buffer = jpype.JClass('java.nio.ByteBuffer') def call(): inst = byte_buffer.allocateDirect(10) Tracer.attach(inst) memoryview(inst) for i in range(100): call() self.assertEqual(Tracer.leaked(), 0) jpype-1.3.0/test/jpypetest/test_legacy.py000066400000000000000000000052351405671516700205460ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import jpype import common import subrun import unittest import os def proxy(s): if not isinstance(s, str): raise TypeError("Fail") return s # This is a test case to exercise all of the paths that pass through # the string conversion to make sure all are exercised. @subrun.TestCase class LegacyTestCase(unittest.TestCase): @classmethod def setUpClass(cls): # Run with automatic string conversion jpype.startJVM(classpath=os.path.abspath( "test/classes"), convertStrings=True) def setUp(self): self._test = jpype.JClass("jpype.str.Test") self._intf = jpype.JClass("jpype.str.StringFunction") def testStaticField(self): s = self._test.staticField self.assertEqual(s, "staticField") self.assertIsInstance(s, str) def testMemberField(self): s = self._test().memberField self.assertEqual(s, "memberField") self.assertIsInstance(s, str) def testStaticMethod(self): s = self._test.staticCall() self.assertEqual(s, "staticCall") self.assertIsInstance(s, str) def testMemberMethod(self): s = self._test().memberCall() self.assertEqual(s, "memberCall") self.assertIsInstance(s, str) def testArrayItem(self): tc = ('apples', 'banana', 'cherries', 'dates', 'elderberry') for i in range(0, 5): s = self._test.array[i] self.assertEqual(s, tc[i]) self.assertIsInstance(s, str) def testArrayRange(self): tc = ('apples', 'banana', 'cherries', 'dates', 'elderberry') slc = self._test.array[1:-1] self.assertEqual(tuple(slc), tc[1:-1]) self.assertIsInstance(slc[1], str) def testProxy(self): p = jpype.JProxy([self._intf], dict={'call': proxy}) r = self._test().callProxy(p, "roundtrip") self.assertEqual(r, "roundtrip") self.assertIsInstance(r, str) jpype-1.3.0/test/jpypetest/test_list.py000066400000000000000000000202341405671516700202510ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import jpype import common class JListTestCase(common.JPypeTestCase): """ Test for methods of java.lang.Map def __getitem__(self, ndx): if isinstance(ndx, slice): start = ndx.start stop = ndx.stop if start < 0: start = self.size() + start if stop < 0: stop = self.size() + stop return self.subList(start, stop) else: if ndx < 0: ndx = self.size() + ndx return self.get(ndx) def __setitem__(self, ndx, v): if isinstance(ndx, slice): start = ndx.start stop = ndx.stop if start < 0: start = self.size() + start if stop < 0: stop = self.size() + stop for i in range(start, stop): self.remove(start) if isinstance(v, collections.abc.Sequence): ndx = start for i in v: self.add(ndx, i) ndx += 1 else: if ndx < 0: ndx = self.size() + ndx self.set(ndx, v) """ def setUp(self): common.JPypeTestCase.setUp(self) self.cls = jpype.JClass('java.util.ArrayList') self.Arrays = jpype.JClass('java.util.Arrays') def testLen(self): obj = self.cls() obj.add(1) obj.add(2) obj.add(3) self.assertEqual(len(obj), 3) def testIter(self): obj = self.cls() obj.add("a") obj.add("b") obj.add("c") self.assertEqual(tuple(i for i in obj), ('a', 'b', 'c')) def testGetItem(self): obj = self.cls() obj.add("a") obj.add("b") obj.add("c") self.assertEqual(obj[1], 'b') def testGetItemSub(self): obj = self.cls() obj.add("a") obj.add("b") obj.add("c") obj.add("d") self.assertEqual(tuple(i for i in obj[1:3]), ('b', 'c')) def testGetItemSlice(self): obj = self.cls() obj.add("a") obj.add("b") obj.add("c") obj.add("d") self.assertEqual(tuple(obj[::1]), ('a', 'b', 'c', 'd')) self.assertEqual(tuple(obj[:-2]), ('a', 'b')) self.assertEqual(tuple(obj[-2:]), ('c', 'd')) with self.assertRaises(TypeError): obj[::2] with self.assertRaises(TypeError): obj[::-1] def testRemoveRange(self): obj = self.cls() obj.add("a") obj.add("b") obj.add("c") obj.add("d") obj[1:3].clear() self.assertEqual(tuple(i for i in obj), ('a', 'd')) def testSetItem(self): obj = self.cls() obj.add("a") obj.add("b") obj.add("c") obj[1] = 'changed' self.assertEqual(tuple(i for i in obj), ('a', 'changed', 'c')) def testDelItem(self): obj = self.cls() obj.add("a") obj.add("b") obj.add("c") del obj[1] self.assertElementsEqual(obj, ('a', 'c')) obj.add("a") obj.add("b") obj.add("c") del obj[1:3] self.assertElementsEqual(obj, ('a', 'b', 'c')) with self.assertRaises(TypeError): del obj[1.0] del obj[-1] self.assertElementsEqual(obj, ('a', 'b')) def testAddAll(self): obj = self.cls() obj.addAll(["a", "b", "c"]) self.assertEqual(tuple(i for i in obj), ('a', 'b', 'c')) obj.addAll(1, ["a", "b", "c"]) self.assertEqual(tuple(i for i in obj), ('a', 'a', 'b', 'c', 'b', 'c')) with self.assertRaises(TypeError): obj.addAll() with self.assertRaises(TypeError): obj.addAll(1, 2, 3) with self.assertRaises(TypeError): obj.addAll(1, 2) with self.assertRaises(TypeError): obj.addAll(1.0, ['a']) def testRemoveAll(self): obj = self.cls() obj.addAll(["a", "b", "c", "d", "e"]) obj.removeAll(["c", "d"]) self.assertEqual(tuple(i for i in obj), ('a', 'b', 'e')) def testRetainAll(self): obj = self.cls() obj.addAll(["a", "b", "c", "d", "e"]) obj.retainAll(["c", "d"]) self.assertEqual(tuple(i for i in obj), ('c', 'd')) def testInit(self): cls = jpype.JClass('java.util.ArrayList') obj = cls(self.Arrays.asList(['a', 'b', 'c'])) self.assertEqual(tuple(i for i in obj), ('a', 'b', 'c')) def testInsert(self): lst = ['A', 'B', 'C'] cls = jpype.JClass('java.util.ArrayList') obj = cls(lst) lst.insert(0, '1') obj.insert(0, '1') lst.insert(3, '2') obj.insert(3, '2') lst.insert(-1, '3') obj.insert(-1, '3') self.assertElementsEqual(obj, lst) def testAppend(self): lst = ['A', 'B', 'C'] cls = jpype.JClass('java.util.ArrayList') obj = cls(lst) obj.append('2') lst.append('2') lst[len(lst):] = ['3'] obj[len(obj):] = ['3'] self.assertElementsEqual(obj, lst) def testReverse(self): lst = ['A', 'B', 'C'] cls = jpype.JClass('java.util.ArrayList') obj = cls(lst) obj.reverse() lst.reverse() self.assertElementsEqual(obj, lst) def testExtend(self): lst = ['A', 'B', 'C'] cls = jpype.JClass('java.util.ArrayList') obj = cls(lst) obj.extend(range(0, 3)) lst.extend(range(0, 3)) self.assertElementsEqual(obj, lst) def testPop(self): lst = ['A', 'B', 'C', 'D', 'E'] cls = jpype.JClass('java.util.ArrayList') obj = cls(lst) self.assertEqual(obj.pop(), lst.pop()) self.assertEqual(obj.pop(0), lst.pop(0)) self.assertEqual(obj.pop(2), lst.pop(2)) self.assertEqual(obj.pop(-1), lst.pop(-1)) self.assertElementsEqual(obj, lst) def testIAdd(self): lst = ['A', 'B', 'C'] cls = jpype.JClass('java.util.ArrayList') obj = cls(lst) obj += 'D' lst += 'D' self.assertElementsEqual(obj, lst) def testAdd(self): lst = ['A', 'B', 'C'] cls = jpype.JClass('java.util.ArrayList') obj = cls(lst) lst2 = lst + ['D'] obj2 = obj + ['D'] self.assertElementsEqual(obj, lst) self.assertElementsEqual(obj2, lst2) def testRemove(self): lst = ['A', 'B', 'C', 'D', 'E'] cls = jpype.JClass('java.util.ArrayList') obj = cls(lst) lst.remove('C') obj.remove('C') with self.assertRaises(ValueError): lst.remove('C') with self.assertRaises(ValueError): obj.remove(1) with self.assertRaises(ValueError): obj.remove('1') with self.assertRaises(ValueError): obj.remove(object()) self.assertElementsEqual(obj, lst) def testProtocol(self): from collections.abc import Sequence, MutableSequence List = jpype.JClass('java.util.List') ArrayList = jpype.JClass('java.util.ArrayList') LinkedList = jpype.JClass('java.util.LinkedList') self.assertTrue(issubclass(List, Sequence)) self.assertTrue(issubclass(List, MutableSequence)) self.assertTrue(issubclass(ArrayList, Sequence)) self.assertTrue(issubclass(ArrayList, MutableSequence)) self.assertTrue(issubclass(LinkedList, Sequence)) self.assertTrue(issubclass(LinkedList, MutableSequence)) jpype-1.3.0/test/jpypetest/test_map.py000066400000000000000000000040131405671516700200500ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import jpype import common class JMapTestCase(common.JPypeTestCase): """ Test for methods of java.lang.Map """ def setUp(self): common.JPypeTestCase.setUp(self) def testLen(self): cls = jpype.JClass('java.util.HashMap') obj = cls() obj.put("a", 1) obj.put("b", 2) obj.put("c", 3) self.assertEqual(len(obj), 3) def testIter(self): cls = jpype.JClass('java.util.TreeMap') obj = cls() obj.put("a", 1) obj.put("b", 2) obj.put("c", 3) self.assertEqual(tuple(i for i in obj), ('a', 'b', 'c')) def testGetItem(self): cls = jpype.JClass('java.util.HashMap') obj = cls() obj.put("a", 1) obj.put("b", 2) obj.put("c", 3) self.assertEqual(obj['b'], 2) def testSetItem(self): cls = jpype.JClass('java.util.HashMap') obj = cls() obj.put("a", 1) obj.put("b", 2) obj.put("c", 3) obj['b'] = 5 self.assertEqual(obj['b'], 5) def testSetItem(self): cls = jpype.JClass('java.util.TreeMap') obj = cls() obj.put("a", 1) obj.put("b", 2) obj.put("c", 3) del obj['b'] self.assertEqual(tuple(i for i in obj), ('a', 'c')) jpype-1.3.0/test/jpypetest/test_module.py000066400000000000000000000075031405671516700205670ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** # Tests for module functionality including failures that cannot # be triggered in normal operations import _jpype import jpype import unittest import subrun import common import unittest.mock as mock @subrun.TestCase(individual=True) class ModuleStartTestCase(unittest.TestCase): def testNoJObject(self): with self.assertRaises(RuntimeError): import jpype del _jpype.JObject jpype.startJVM() def testNoJInterface(self): with self.assertRaises(RuntimeError): import jpype del _jpype.JInterface jpype.startJVM() def testNoJArray(self): with self.assertRaises(RuntimeError): import jpype del _jpype.JArray jpype.startJVM() def testNoJException(self): with self.assertRaises(RuntimeError): import jpype del _jpype.JException jpype.startJVM() def testNoJClassPre(self): with self.assertRaises(RuntimeError): import jpype del _jpype._jclassPre jpype.startJVM() def testNoJClassPost(self): with self.assertRaises(RuntimeError): import jpype del _jpype._jclassPost jpype.startJVM() def testNoMethodAnnotations(self): with self.assertRaises(RuntimeError): import jpype del _jpype.getMethodAnnotations jpype.startJVM() def testNoMethodCode(self): with self.assertRaises(RuntimeError): import jpype del _jpype.getMethodCode jpype.startJVM() def testShutdown(self): import jpype jpype.startJVM(convertStrings=False) jpype.shutdownJVM() class ModuleTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) def testIsPackage(self): self.assertTrue(_jpype.isPackage("java")) self.assertFalse(_jpype.isPackage("jva")) with self.assertRaises(TypeError): _jpype.isPackage(object()) def testGetClass(self): self.assertIsInstance(_jpype._getClass("java.lang.String"), _jpype._JClass) with self.assertRaises(TypeError): _jpype._getClass(object()) def testHasClass(self): self.assertTrue(_jpype._hasClass("java.lang.String")) with self.assertRaises(TypeError): _jpype._hasClass(object()) class JInitTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) def testJInit(self): with mock.patch("_jpype.isStarted") as started: started.return_value = False self.assertEqual(len(jpype._jinit.JInitializers), 0) A = [] def func(): A.append(1) jpype.onJVMStart(func) self.assertEqual(len(A), 0) self.assertEqual(jpype._jinit.JInitializers[0], func) started.return_value = True jpype.onJVMStart(func) self.assertEqual(len(A), 1) jpype._jinit.runJVMInitializers() self.assertEqual(len(A), 2) jpype-1.3.0/test/jpypetest/test_module2.py000066400000000000000000000044751405671516700206560ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import jpype import _jpype import common class ModuleTestCase2(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) def testMonitorOnNull(self): value = jpype.JObject(None) with self.assertRaises(TypeError): _jpype._JMonitor(value) def testMonitorOnString(self): value = jpype.JString("foo") with self.assertRaises(TypeError): _jpype._JMonitor(value) def testMonitorOnPrim(self): value = jpype.JInt(1) with self.assertRaises(TypeError): _jpype._JMonitor(value) def testMonitorInitBad(self): with self.assertRaises(TypeError): _jpype._JMonitor() def testMonitorInitBad2(self): with self.assertRaises(TypeError): _jpype._JMonitor(None) def testMonitorStr(self): obj = jpype.java.lang.Object() monitor = _jpype._JMonitor(obj) self.assertIsInstance(str(monitor), str) def testProxyInitBad(self): with self.assertRaises(TypeError): _jpype._JProxy(None) def testProxyInitBad2(self): with self.assertRaises(TypeError): _jpype._JProxy(None, None, None) def testProxyInitBad3(self): with self.assertRaises(TypeError): _jpype._JProxy(None, None, tuple([None, None])) def testProxyNoInterfaces(self): with self.assertRaises(TypeError): proxy = _jpype._JProxy(None, None, tuple()) def testValueStr(self): obj = jpype.JClass("java.lang.Object")() self.assertIsInstance(str(obj), str) jpype-1.3.0/test/jpypetest/test_mro.py000066400000000000000000000020321405671516700200670ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** from jpype.types import * from jpype import java import sys import common class MroTestCase(common.JPypeTestCase): def testMro(self): C = JClass('jpype.mro.C') def testMultipleInterfaces(self): j = JClass("jpype.mro.MultipleInterfaces") myinstance = j() jpype-1.3.0/test/jpypetest/test_number.py000066400000000000000000000050361405671516700205710ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import sys import jpype import common import random import _jpype import jpype from jpype import java from jpype.types import * try: import numpy as np except ImportError: pass class JNumberTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) self.cls = JClass("jpype.common.Fixture") self.fixture = self.cls() def testJavaPrimitives(self): self.assertIsInstance( self.fixture.callNumber(JByte(1)), java.lang.Byte) self.assertIsInstance( self.fixture.callNumber(JShort(1)), java.lang.Short) self.assertIsInstance( self.fixture.callNumber(JInt(1)), java.lang.Integer) self.assertIsInstance( self.fixture.callNumber(JLong(1)), java.lang.Long) self.assertIsInstance( self.fixture.callNumber(JFloat(1)), java.lang.Float) self.assertIsInstance(self.fixture.callNumber( JDouble(1)), java.lang.Double) def testPythonPrimitives(self): self.assertIsInstance(self.fixture.callNumber(1), java.lang.Long) self.assertIsInstance(self.fixture.callNumber(1.0), java.lang.Double) @common.requireNumpy def testNumpyPrimitives(self): self.assertIsInstance( self.fixture.callNumber(np.int8(1)), java.lang.Byte) self.assertIsInstance(self.fixture.callNumber( np.int16(1)), java.lang.Short) self.assertIsInstance(self.fixture.callNumber( np.int32(1)), java.lang.Integer) self.assertIsInstance(self.fixture.callNumber( np.int64(1)), java.lang.Long) self.assertIsInstance(self.fixture.callNumber( np.float32(1)), java.lang.Float) self.assertIsInstance(self.fixture.callNumber( np.float64(1)), java.lang.Double) jpype-1.3.0/test/jpypetest/test_numeric.py000066400000000000000000000121431405671516700207400ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import _jpype import jpype from jpype import JPackage, java from jpype.types import * import common class NumericTestCase(common.JPypeTestCase): def testMathAbs(self): self.assertEqual(java.lang.Math.abs(-10), 10) def testDoubleConversion(self): f = java.lang.Float.MAX_VALUE * 2 self.assertTrue(JClass("jpype.numeric.NumericTest").doubleIsTwiceMaxFloat(f)) def testDoubleIsProperlyConverted(self): self.assertTrue(java.lang.Double.POSITIVE_INFINITY != 0.0) self.assertTrue(java.lang.Double.MAX_VALUE != 0.0) self.assertTrue(java.lang.Double.NaN != 0.0) self.assertTrue(java.lang.Double.NEGATIVE_INFINITY != 0.0) def testCompareNullLong(self): null = JObject(None, java.lang.Integer) self.assertEqual(null, None) self.assertNotEqual(null, object()) with self.assertRaisesRegex(TypeError, "null"): null > 0 with self.assertRaisesRegex(TypeError, "null"): null < 0 with self.assertRaisesRegex(TypeError, "null"): null >= 0 with self.assertRaisesRegex(TypeError, "null"): null <= 0 def testCompareNullFloat(self): null = JObject(None, java.lang.Double) self.assertEqual(null, None) self.assertNotEqual(null, object()) with self.assertRaisesRegex(TypeError, "null"): null > 0 with self.assertRaisesRegex(TypeError, "null"): null < 0 with self.assertRaisesRegex(TypeError, "null"): null >= 0 with self.assertRaisesRegex(TypeError, "null"): null <= 0 def testHashNull(self): null = JObject(None, java.lang.Integer) self.assertEqual(hash(null), hash(None)) null = JObject(None, java.lang.Float) self.assertEqual(hash(null), hash(None)) @common.requireInstrumentation def testJPNumber_new(self): _jpype.fault("PyJPNumber_new") class MyNum(_jpype._JNumberLong, internal=True): pass with self.assertRaisesRegex(SystemError, "fault"): JInt(1) with self.assertRaises(TypeError): MyNum(1) _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): JInt(1) JInt(1) @common.requireInstrumentation def testJPNumberLong_int(self): ji = JInt(1) _jpype.fault("PyJPNumberLong_int") with self.assertRaisesRegex(SystemError, "fault"): int(ji) _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): int(ji) int(ji) @common.requireInstrumentation def testJPNumberLong_float(self): ji = JInt(1) _jpype.fault("PyJPNumberLong_float") with self.assertRaisesRegex(SystemError, "fault"): float(ji) _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): float(ji) float(ji) @common.requireInstrumentation def testJPNumberLong_str(self): ji = JInt(1) _jpype.fault("PyJPNumberLong_str") with self.assertRaisesRegex(SystemError, "fault"): str(ji) _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): str(ji) str(ji) @common.requireInstrumentation def testJPNumberLong_repr(self): ji = JInt(1) _jpype.fault("PyJPNumberLong_repr") with self.assertRaisesRegex(SystemError, "fault"): repr(ji) _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): repr(ji) repr(ji) @common.requireInstrumentation def testJPNumberLong_compare(self): ji = JInt(1) _jpype.fault("PyJPNumberLong_compare") with self.assertRaisesRegex(SystemError, "fault"): ji == 1 _jpype.fault("PyJPModule_getContext") with self.assertRaisesRegex(SystemError, "fault"): ji == 1 ji == 1 @common.requireInstrumentation def testJPNumberLong_hash(self): ji = JInt(1) _jpype.fault("PyJPNumberLong_hash") with self.assertRaises(SystemError): hash(ji) _jpype.fault("PyJPModule_getContext") with self.assertRaises(SystemError): hash(ji) hash(ji) jpype-1.3.0/test/jpypetest/test_objectwrapper.py000066400000000000000000000124711405671516700221510ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import jpype from jpype.types import * from jpype import java import common #import os #import sys class ObjectWrapperTestCase(common.JPypeTestCase): def testCallOverloads(self): # build the harness h = JClass("jpype.objectwrapper.Test1")() o = java.lang.Integer(1) self.assertEqual(h.Method1(JObject(o, java.lang.Number)), 1) self.assertEqual(h.Method1(o), 2) self.assertEqual(h.Method1(JObject(java.lang.Integer(1), java.lang.Object)), 3) self.assertEqual(h.Method1(JString("")), 4) def testDefaultTypeNameString(self): self.assertEqual(type(JObject("123")), jpype.JClass("java.lang.String")) def testDefaultTypeNameBoolean(self): self.assertEqual(type(JObject(True)), jpype.JClass("java.lang.Boolean")) self.assertEqual(type(JObject(False)), jpype.JClass("java.lang.Boolean")) def testPassingClassTypeSucceeds(self): h = JClass("jpype.objectwrapper.Test1")() # Select a convenient java.lang.Class object class_obj = h.getClass() # Check that funneling Class obj through java doesn't convert to null result = h.ReturnObject(class_obj) self.assertEqual(class_obj, result) self.assertNotEqual(result, None) def testWrapJavaClass(self): o = java.lang.String self.assertEqual(type(JObject(o)), jpype.JClass("java.lang.Class")) def testWrapJavaObject(self): o = java.lang.String("foo") self.assertEqual(type(JObject(o)), jpype.JClass("java.lang.String")) def testWrapJavaObjectCast(self): o = java.lang.String("foo") c = java.lang.Object self.assertEqual(type(JObject(o, c)), jpype.JClass("java.lang.Object")) def testWrapJavaObjectCastFail(self): o = java.lang.Object() c = java.lang.Math with self.assertRaises(TypeError): f = JObject(o, c) def testWrapJavaPrimitiveCast(self): c = java.lang.Object self.assertEqual(type(JObject("foo", c)), jpype.JClass("java.lang.Object")) self.assertEqual(type(JObject(True, c)), jpype.JClass("java.lang.Object")) self.assertEqual(type(JObject(False, c)), jpype.JClass("java.lang.Object")) self.assertEqual(type(JObject(1, c)), jpype.JClass("java.lang.Object")) self.assertEqual(type(JObject(1.0, c)), jpype.JClass("java.lang.Object")) def testWrapJavaPrimitiveBox(self): self.assertEqual(type(JObject("foo", JString)), jpype.JClass("java.lang.String")) self.assertEqual(type(JObject(1, JInt)), jpype.JClass("java.lang.Integer")) self.assertEqual(type(JObject(1, JLong)), jpype.JClass("java.lang.Long")) self.assertEqual(type(JObject(1.0, JFloat)), jpype.JClass("java.lang.Float")) self.assertEqual(type(JObject(1.0, JDouble)), jpype.JClass("java.lang.Double")) self.assertEqual(type(JObject(1, JShort)), jpype.JClass("java.lang.Short")) def testJObjectBadType(self): class Fred(object): pass with self.assertRaises(TypeError): jpype.JObject(1, Fred) def testJObjectUnknownObject(self): class Fred(object): pass with self.assertRaises(TypeError): jpype.JObject(Fred()) # def testMakeSureWeCanLoadAllClasses(self): # def get_system_jars(): # for dirpath,_,files in os.walk(jpype.java.lang.System.getProperty("java.home")): # for file in files: # if file.endswith('.jar'): # yield (os.path.join(dirpath,file)) # for jar in get_system_jars(): # classes = [x.getName() for x in jpype.java.util.jar.JarFile(jar).entries() if x.getName().endswith('.class')] # classes = [x.replace('/','.')[:-6] for x in classes] # for clazz in classes: # try: # jpype.JClass(clazz) # except jpype.JavaException as exception: # if not 'not found' in exception.message(): # print(clazz) # print (exception.message()) # #print (exception.stacktrace()) # except: # print(sys.exc_info()[0]) # pass jpype-1.3.0/test/jpypetest/test_opts.py000077500000000000000000000012041405671516700202620ustar00rootroot00000000000000import sys import jpype import common # This is an example of how to pass arguments to pytest. # Options are defined in the file conftest.py and # passed the a fixture function. This fixture function # is then applied to each TestCase class. # # class OptsTestCase(common.JPypeTestCase): # # def setUp(self): # common.JPypeTestCase.setUp(self) # # def testOpts(self): # self.assertTrue(hasattr(self, "_jar")) # self.assertTrue(hasattr(self, "_convertStrings")) # # def testConvertStrings(self): # self.assertTrue(self._convertStrings) # # def testJar(self): # self.assertEqual(self._jar, "foo") jpype-1.3.0/test/jpypetest/test_overloads.py000066400000000000000000000225051405671516700212770ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import jpype from jpype import JString, java, JArray, JClass, JByte, JShort, JInt, JLong, JFloat, JDouble, JChar, JBoolean, JObject import sys import time import common java = jpype.java class OverloadTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) self.__jp = self.jpype.overloads self._aclass = JClass('jpype.overloads.Test1$A') self._bclass = JClass('jpype.overloads.Test1$B') self._cclass = JClass('jpype.overloads.Test1$C') self._a = self._aclass() self._b = self._bclass() self._c = self._cclass() self._i1impl = JClass('jpype.overloads.Test1$I1Impl')() self._i2impl = JClass('jpype.overloads.Test1$I2Impl')() self._i3impl = JClass('jpype.overloads.Test1$I3Impl')() self._i4impl = JClass('jpype.overloads.Test1$I4Impl')() self._i5impl = JClass('jpype.overloads.Test1$I5Impl')() self._i6impl = JClass('jpype.overloads.Test1$I6Impl')() self._i7impl = JClass('jpype.overloads.Test1$I7Impl')() self._i8impl = JClass('jpype.overloads.Test1$I8Impl')() def testMostSpecificInstanceMethod(self): test1 = self.__jp.Test1() self.assertEqual('A', test1.testMostSpecific(self._a)) self.assertEqual('B', test1.testMostSpecific(self._b)) self.assertEqual('B', test1.testMostSpecific(self._c)) self.assertEqual('B', test1.testMostSpecific(None)) def testForceOverloadResolution(self): test1 = self.__jp.Test1() self.assertEqual('A', test1.testMostSpecific( JObject(self._c, self._aclass))) self.assertEqual('B', test1.testMostSpecific( JObject(self._c, self._bclass))) # JObject wrapper forces exact matches #self.assertRaisesRegex(TypeError, 'No matching overloads found', test1.testMostSpecific, JObject(self._c, self._cclass)) self.assertEqual('A', test1.testMostSpecific( JObject(self._c, 'jpype.overloads.Test1$A'))) self.assertEqual('B', test1.testMostSpecific( JObject(self._c, 'jpype.overloads.Test1$B'))) # JObject wrapper forces exact matches #self.assertRaisesRegex(TypeError, 'No matching overloads found', test1.testMostSpecific, JObject(self._c, 'jpype.overloads.Test1$C')) def testVarArgsCall(self): test1 = self.__jp.Test1() self.assertEqual('A,B...', test1.testVarArgs(self._a, [])) self.assertEqual('A,B...', test1.testVarArgs(self._a, None)) self.assertEqual('A,B...', test1.testVarArgs(self._a, [self._b])) self.assertEqual('A,A...', test1.testVarArgs(self._a, [self._a])) self.assertEqual('A,B...', test1.testVarArgs( self._a, [self._b, self._b])) self.assertEqual('B,B...', test1.testVarArgs( self._b, [self._b, self._b])) self.assertEqual('B,B...', test1.testVarArgs( self._c, [self._c, self._b])) self.assertEqual('B,B...', test1.testVarArgs( self._c, JArray(self._cclass, 1)([self._c, self._c]))) self.assertEqual('B,B...', test1.testVarArgs(self._c, None)) self.assertEqual('B,B...', test1.testVarArgs(None, None)) def testPrimitive(self): test1 = self.__jp.Test1() intexpectation = 'int' if not sys.version_info[0] > 2 and sys.maxint == 2**31 - 1 else 'long' # FIXME it is not possible to determine if this is bool/char/byte currently #self.assertEqual(intexpectation, test1.testPrimitive(5)) #self.assertEqual('long', test1.testPrimitive(2**31)) self.assertEqual('byte', test1.testPrimitive(JByte(5))) self.assertEqual('Byte', test1.testPrimitive(java.lang.Byte(5))) self.assertEqual('short', test1.testPrimitive(JShort(5))) self.assertEqual('Short', test1.testPrimitive(java.lang.Short(5))) self.assertEqual('int', test1.testPrimitive(JInt(5))) self.assertEqual('Integer', test1.testPrimitive(java.lang.Integer(5))) self.assertEqual('long', test1.testPrimitive(JLong(5))) self.assertEqual('Long', test1.testPrimitive(java.lang.Long(5))) self.assertEqual('float', test1.testPrimitive(JFloat(5))) self.assertEqual('Float', test1.testPrimitive(java.lang.Float(5.0))) self.assertEqual('double', test1.testPrimitive(JDouble(5))) self.assertEqual('Double', test1.testPrimitive(java.lang.Double(5.0))) self.assertEqual('boolean', test1.testPrimitive(JBoolean(5))) self.assertEqual('Boolean', test1.testPrimitive(java.lang.Boolean(5))) self.assertEqual('char', test1.testPrimitive(JChar('5'))) self.assertEqual('Character', test1.testPrimitive( java.lang.Character('5'))) def testInstanceVsClassMethod(self): # this behaviour is different than the one in java, so maybe we should change it? test1 = self.__jp.Test1() self.assertEqual( 'static B', self.__jp.Test1.testInstanceVsClass(self._c)) self.assertEqual('instance A', test1.testInstanceVsClass(self._c)) # here what would the above resolve to in java self.assertEqual( 'static B', self.__jp.Test1.testJavaInstanceVsClass()) def testInterfaces1(self): test1 = self.__jp.Test1() self.assertRaisesRegex( TypeError, 'Ambiguous overloads found', test1.testInterfaces1, self._i4impl) self.assertEqual('I2', test1.testInterfaces1( JObject(self._i4impl, 'jpype.overloads.Test1$I2'))) self.assertEqual('I3', test1.testInterfaces1( JObject(self._i4impl, 'jpype.overloads.Test1$I3'))) def testInterfaces2(self): test1 = self.__jp.Test1() self.assertEqual('I4', test1.testInterfaces2(self._i4impl)) self.assertEqual('I2', test1.testInterfaces2( JObject(self._i4impl, 'jpype.overloads.Test1$I2'))) self.assertEqual('I3', test1.testInterfaces2( JObject(self._i4impl, 'jpype.overloads.Test1$I3'))) def testInterfaces3(self): test1 = self.__jp.Test1() self.assertRaisesRegex( TypeError, 'Ambiguous overloads found', test1.testInterfaces3, self._i8impl) self.assertEqual('I4', test1.testInterfaces3(self._i6impl)) self.assertRaisesRegex( TypeError, 'No matching overloads found', test1.testInterfaces3, self._i3impl) def testInterfaces4(self): test1 = self.__jp.Test1() self.assertEqual('I8', test1.testInterfaces4(None)) self.assertEqual('I1', test1.testInterfaces4(self._i1impl)) self.assertEqual('I2', test1.testInterfaces4(self._i2impl)) self.assertEqual('I3', test1.testInterfaces4(self._i3impl)) self.assertEqual('I4', test1.testInterfaces4(self._i4impl)) self.assertEqual('I5', test1.testInterfaces4(self._i5impl)) self.assertEqual('I6', test1.testInterfaces4(self._i6impl)) self.assertEqual('I7', test1.testInterfaces4(self._i7impl)) self.assertEqual('I8', test1.testInterfaces4(self._i8impl)) def testClassVsObject(self): test1 = self.__jp.Test1() self.assertEqual('Object', test1.testClassVsObject(self._i4impl)) self.assertEqual('Object', test1.testClassVsObject(1)) self.assertEqual('Class', test1.testClassVsObject(None)) self.assertEqual('Class', test1.testClassVsObject( JClass('jpype.overloads.Test1$I4Impl'))) self.assertEqual('Class', test1.testClassVsObject( JClass('jpype.overloads.Test1$I3'))) def testStringArray(self): test1 = self.__jp.Test1() self.assertEqual('Object', test1.testStringArray(self._i4impl)) self.assertEqual('Object', test1.testStringArray(1)) self.assertRaisesRegex( TypeError, 'Ambiguous overloads found', test1.testStringArray, None) self.assertEqual('String', test1.testStringArray('somestring')) self.assertEqual('String[]', test1.testStringArray([])) self.assertEqual('String[]', test1.testStringArray(['a', 'b'])) self.assertEqual('String[]', test1.testStringArray( JArray(java.lang.String, 1)(['a', 'b']))) self.assertEqual('Object', test1.testStringArray( JArray(JInt, 1)([1, 2]))) def testListVSArray(self): test1 = self.__jp.Test1() self.assertEqual('String[]', test1.testListVSArray(['a', 'b'])) self.assertEqual('List', test1.testListVSArray( jpype.java.util.Arrays.asList(['a', 'b']))) def testDefaultMethods(self): try: testdefault = JClass('jpype.overloads.Test1$DefaultC')() except: pass else: self.assertEqual('B', testdefault.defaultMethod()) jpype-1.3.0/test/jpypetest/test_pickle.py000066400000000000000000000051741405671516700205530ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import jpype from jpype import java from jpype.pickle import JPickler, JUnpickler import pickle import sys import common import unittest def dump(fname): with open(fname, "rb") as fd: data = fd.read() out = ["%02x" % i for i in data] print("Pickle fail", " ".join(out), file=sys.stderr) class PickleTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) def testString(self): try: s = java.lang.String("test") with open("test.pic", "wb") as fd: JPickler(fd).dump(s) with open("test.pic", "rb") as fd: s2 = JUnpickler(fd).load() except pickle.UnpicklingError: dump("test.pic") self.assertEqual(s, s2) def testList(self): s = java.util.ArrayList() s.add("test") s.add("this") try: with open("test.pic", "wb") as fd: JPickler(fd).dump(s) with open("test.pic", "rb") as fd: s2 = JUnpickler(fd).load() except pickle.UnpicklingError: dump("test.pic") self.assertEqual(s2.get(0), "test") self.assertEqual(s2.get(1), "this") def testMixed(self): d = {} d["array"] = java.util.ArrayList() d["string"] = java.lang.String("food") try: with open("test.pic", "wb") as fd: JPickler(fd).dump(d) with open("test.pic", "rb") as fd: d2 = JUnpickler(fd).load() except pickle.UnpicklingError: dump("test.pic") self.assertEqual(d2['string'], "food") self.assertIsInstance(d2['array'], java.util.ArrayList) def testFail(self): s = java.lang.Object() with self.assertRaises(java.io.NotSerializableException): with open("test.pic", "wb") as fd: JPickler(fd).dump(s) jpype-1.3.0/test/jpypetest/test_properties.py000066400000000000000000000111771405671516700215000ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import subrun import unittest import jpype @subrun.TestCase class PropertiesTestCase(unittest.TestCase): @classmethod def setUpClass(cls): import jpype.beans jpype.startJVM(classpath="test/classes", convertStrings=False) def setUp(self): self._bean = jpype.JClass('jpype.properties.TestBean')() def testPropertyPublicMethodOverlap(self): self._bean.setProperty1("val") self.assertEqual("getsetval", self._bean.getProperty1()) def testPublicMethodPropertyOverlap(self): self.assertEqual("method", self._bean.property1()) def testPropertyProtectedMethodOverlapInvisibleAttribute(self): self._bean.property2 = "val" self.assertEqual("getsetval", self._bean.property2) def testProtectedMethodPropertyOverlapInvisibleAttribute(self): self.assertFalse(hasattr(self._bean.property2, '__call__')) def testPropertyProtectedMethodOverlapAttribute(self): self._bean.property3 = "val" self.assertEqual("getsetval", self._bean.property3) def testProtectedMethodPropertyOverlapAttribute(self): self.assertFalse(hasattr(self._bean.property3, '__call__')) def testPropertyProtectedMethodOverlapAttributeSet(self): self._bean.setProperty3("val") self.assertEqual("getsetval", self._bean.property3) def testPropertyProtectedMethodOverlapAttributeGet(self): self._bean.property3 = "val" self.assertEqual("getsetval", self._bean.getProperty3()) def testPrivateAttributeNoThreeCharacterMethodMatchCollision(self): self._bean.property4 = "val" self.assertEqual("abcval", self._bean.abcProperty4()) def testPropertyOnlySetter(self): self._bean.property5 = "val" self.assertEqual("returnsetval", self._bean.returnProperty5()) def testPropertyOnlySetterSet(self): self._bean.setProperty5("val") with self.assertRaises(AttributeError): self.assertEqual("setval", self._bean.property5) def testPropertyDifferentAttribute(self): self._bean.property6 = "val" self.assertEqual("getsetval", self._bean.property6) self.assertEqual("setval", self._bean.property7) def testProertyDifferentAttributeSet(self): self._bean.setProperty6("val") self.assertEqual("getsetval", self._bean.property6) self.assertEqual("setval", self._bean.property7) def testHasProperties(self): cls = jpype.JClass("jpype.properties.TestBean") obj = cls() self.assertTrue(isinstance(cls.__dict__['propertyMember'], property)) self.assertTrue(isinstance(cls.__dict__['readOnly'], property)) self.assertTrue(isinstance(cls.__dict__['writeOnly'], property)) self.assertTrue(isinstance(cls.__dict__['with_'], property)) def testPropertyMember(self): obj = jpype.JClass("jpype.properties.TestBean")() obj.propertyMember = "q" self.assertEqual(obj.propertyMember, "q") def testPropertyKeyword(self): obj = jpype.JClass("jpype.properties.TestBean")() obj.with_ = "a" self.assertEqual(obj.with_, "a") self.assertEqual(obj.m5, "a") def testPropertyReadOnly(self): # Test readonly obj = jpype.JClass("jpype.properties.TestBean")() obj.m3 = "b" self.assertEqual(obj.readOnly, "b") with self.assertRaises(AttributeError): obj.readOnly = "c" def testPropertyWriteOnly(self): # Test writeonly obj = jpype.JClass("jpype.properties.TestBean")() obj.writeOnly = "c" self.assertEqual(obj.m4, "c") with self.assertRaises(AttributeError): x = obj.writeOnly def testNoProperties(self): cls = jpype.JClass("jpype.properties.TestBean") with self.assertRaises(KeyError): cls.__dict__['failure1'] with self.assertRaises(KeyError): cls.__dict__['failure2'] jpype-1.3.0/test/jpypetest/test_proxy.py000066400000000000000000000405361405671516700204660ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import contextlib import sys from jpype import * import common import subrun def _testMethod1(): return 33 def _testMethod2(): return 32 def _testMethod3(): return "Foo" class C: def testMethod1(self): return 43 def testMethod2(self): return 42 def testMethod3(self): return "Bar" def write(self, bytes, start, length): return bytes, start, length class ThreadCallbackImpl: def __init__(self): self.values = [] def notifyValue(self, val): self.values.append(val) class ProxyTestCase(common.JPypeTestCase): def setUp(self): super(ProxyTestCase, self).setUp() self.package = JPackage("jpype.proxy") self._triggers = self.package.ProxyTriggers def testProxyDecl(self): d = { 'testMethod1': _testMethod1, 'testMethod2': _testMethod2, } itf1 = self.package.TestInterface1 itf2 = self.package.TestInterface2 proxy = JProxy(itf1, dict=d) proxy = JProxy([itf1], dict=d) proxy = JProxy([itf1, itf2], dict=d) proxy = JProxy("jpype.proxy.TestInterface1", dict=d) proxy = JProxy(["jpype.proxy.TestInterface1"], dict=d) def testNotImplemented(self): itf1 = self.package.TestInterface1 proxy = JObject(JProxy(itf1, dict={}), itf1) with self.assertRaises(JClass("java.lang.NoSuchMethodError")): proxy.testMethod1() def testProxyRoundTrip(self): @JImplements(java.lang.Runnable) class MyRun(object): @JOverride def run(self): pass al = JClass('java.util.ArrayList')() runner = MyRun() al.add(runner) self.assertIs(al.get(0), runner) def testProxyLeak(self): @JImplements(java.lang.Runnable) class MyRun(object): @JOverride def run(self): pass al = JClass('java.util.ArrayList')() runner = MyRun() al.add(runner) initial = sys.getrefcount(runner) for i in range(0, 10): self.assertIs(al.get(0), runner) final = sys.getrefcount(runner) self.assertEqual(initial, final) def testProxyDeclFail1(self): itf1 = self.package.TestInterface1 # Missing required arguments with self.assertRaisesRegex(TypeError, "must be specified"): proxy = JProxy(itf1) def testProxyDeclFail2(self): itf1 = self.package.TestInterface1 # Not a str, JClass, or str with self.assertRaisesRegex(TypeError, "is not a Java interface"): proxy = JProxy(int(1), dict={}) def testProxyImplementsForm1(self): itf1 = self.package.TestInterface1 itf2 = self.package.TestInterface2 @JImplements(itf1) class MyImpl(object): @JOverride def testMethod1(self): pass def testProxyImplementsForm2(self): itf1 = self.package.TestInterface1 itf2 = self.package.TestInterface2 @JImplements(itf1, itf2) class MyImpl(object): @JOverride def testMethod1(self): pass @JOverride def testMethod2(self): pass @JOverride def write(self): pass def testProxyImplementsForm3(self): @JImplements("jpype.proxy.TestInterface1") class MyImpl(object): @JOverride def testMethod1(self): pass def testProxyImplementsForm4(self): @JImplements("jpype.proxy.TestInterface1", "jpype.proxy.TestInterface2") class MyImpl(object): @JOverride def testMethod1(self): pass @JOverride def testMethod2(self): pass @JOverride def write(self): pass def testProxyImplementsFail1(self): with self.assertRaisesRegex(TypeError, "least one Java interface"): # Empty interfaces @JImplements() class MyImpl(object): @JOverride def testMethod1(self): pass def testProxyImplementsFail2(self): with self.assertRaisesRegex(TypeError, "is not a Java interface"): # Wrong type @JImplements(int(1)) class MyImpl(object): @JOverride def testMethod1(self): pass def testProxyImplementsFail3(self): with self.assertRaisesRegex(NotImplementedError, "requires method"): # Missing implementation @JImplements("jpype.proxy.TestInterface1") class MyImpl(object): def testMethod1(self): pass def testProxyImplementsFail4(self): with self.assertRaisesRegex(TypeError, "is not a Java interface"): # extends @JImplements("java.lang.StringBuilder") class MyImpl(object): def testMethod1(self): pass def testProxyWithDict(self): d = { 'testMethod1': _testMethod1, 'testMethod2': _testMethod2, } itf1 = self.package.TestInterface1 itf2 = self.package.TestInterface2 proxy = JProxy([itf1, itf2], dict=d) result = self._triggers.testProxy(proxy) expected = ['Test Method1 = 33', 'Test Method2 = 32'] self.assertSequenceEqual(result, expected) def testProxyWithDictInherited(self): d = { 'testMethod2': _testMethod2, 'testMethod3': _testMethod3, } itf3 = self.package.TestInterface3 proxy = JProxy(itf3, dict=d) result = self._triggers.testProxy(proxy) expected = ['Test Method2 = 32', 'Test Method3 = Foo'] self.assertSequenceEqual(result, expected) def testProxyWithInst(self): itf3 = self.package.TestInterface3 c = C() proxy = JProxy(itf3, inst=c) result = self._triggers.testProxy(proxy) expected = ['Test Method2 = 42', 'Test Method3 = Bar'] self.assertSequenceEqual(result, expected) def testProxyWithThread(self): itf = self.package.TestThreadCallback tcb = ThreadCallbackImpl() proxy = JProxy(itf, inst=tcb) self._triggers().testProxyWithThread(proxy) self.assertEqual(tcb.values, ['Waiting for thread start', '1', '2', '3', 'Thread finished']) def testProxyWithArguments(self): itf2 = self.package.TestInterface2 c = C() proxy = JProxy(itf2, inst=c) result = self._triggers().testCallbackWithParameters(proxy) bytes, start, length = result self.assertSequenceEqual(bytes, [1, 2, 3, 4]) self.assertEqual(start, 12) self.assertEqual(length, 13) def testProxyWithMultipleInterface(self): itf1 = self.package.TestInterface1 itf2 = self.package.TestInterface2 c = C() proxy = JProxy([itf1, itf2], inst=c) try: result = self._triggers.testProxy(proxy) except Exception as ex: raise ex expected = ['Test Method1 = 43', 'Test Method2 = 42'] self.assertSequenceEqual(result, expected) def testProxyWithMultipleInterfaceInherited(self): itf2 = self.package.TestInterface2 itf3 = self.package.TestInterface3 c = C() proxy = JProxy([itf2, itf3], inst=c) result = self._triggers().testCallbackWithParameters(proxy) bytes, start, length = result self.assertSequenceEqual(bytes, [1, 2, 3, 4]) self.assertEqual(start, 12) self.assertEqual(length, 13) def testProxyJObjectCast(self): jrun = JClass('java.lang.Runnable') jobj = JClass("java.lang.Object") @JImplements(jrun) class MyClass(object): @JOverride def run(self): pass self.assertIsInstance(JObject(MyClass(), jrun), jrun) self.assertIsInstance(JObject(MyClass()), jobj) def testProxyConvert(self): # This was tests that arguments and "self" both # convert to the same object TestInterface5 = JClass("jpype.proxy.TestInterface5") ProxyTriggers = JClass("jpype.proxy.ProxyTriggers") @JImplements(TestInterface5) class Bomb(object): @JOverride def equals(self, other): return type(self) == type(other) b = Bomb() t = ProxyTriggers() self.assertTrue(t.testEquals(b)) def testProxyFail(self): with self.assertRaises(TypeError): JProxy(inst=object(), dict={}, intf="java.io.Serializable") def testValid(self): @JImplements("java.util.Comparator") class ValidComparator(object): @JOverride def compare(self, _o1, _o2): return 0 @JOverride def equals(self, _obj): return True arr = JArray(JString)(["a", "b"]) java.util.Arrays.sort(arr, ValidComparator()) def testRaisePython(self): @JImplements("java.util.Comparator") class RaiseException(object): def __init__(self, exc): self.exc = exc @JOverride def compare(self, _o1, _o2): raise self.exc("nobody expects the Python exception!") @JOverride def equals(self, _obj): return True arr = JArray(JString)(["a", "b"]) with self.assertRaises(TypeError): java.util.Arrays.sort(arr, RaiseException(TypeError)) with self.assertRaises(ValueError): java.util.Arrays.sort(arr, RaiseException(ValueError)) with self.assertRaises(SyntaxError): java.util.Arrays.sort(arr, RaiseException(SyntaxError)) with self.assertRaises(java.lang.RuntimeException): java.util.Arrays.sort( arr, RaiseException(java.lang.RuntimeException)) def testBad(self): @JImplements("java.util.Comparator") class TooManyParams(object): @JOverride def compare(self, _o1, _o2, _o3): return 0 @JOverride def equals(self, _obj): return True @JImplements("java.util.Comparator") class TooFewParams(object): @JOverride def compare(self, _o1): return 0 @JOverride def equals(self, _obj): return True arr = JArray(JString)(["a", "b"]) with self.assertRaises(TypeError): java.util.Arrays.sort(arr, TooManyParams()) with self.assertRaises(TypeError): java.util.Arrays.sort(arr, TooFewParams()) def testUnwrap(self): fixture = JClass("jpype.common.Fixture")() @JImplements("java.io.Serializable") class Q(object): pass q = Q() self.assertEqual(JProxy.unwrap(q), q) q2 = fixture.callObject(q) self.assertEqual(JProxy.unwrap(q2), q) class R(object): pass r = R() s = JProxy("java.io.Serializable", inst=r) self.assertEqual(JProxy.unwrap(s), r) s2 = fixture.callObject(s) self.assertEqual(JProxy.unwrap(s2), r) def testConvert(self): fixture = JClass("jpype.common.Fixture")() class R(object): pass r = R() # Verify with not asked to auto convert it doesn't s = JProxy("java.io.Serializable", inst=r) s2 = fixture.callObject(s) self.assertEqual(s2, s) self.assertNotEqual(s2, r) # Verify that when asked to auto convert it does s = JProxy("java.io.Serializable", inst=r, convert=True) s2 = fixture.callObject(s) self.assertNotEqual(s2, s) self.assertEqual(s2, r) def testMethods(self): fixture = JClass("jpype.common.Fixture")() @JImplements("java.io.Serializable") class R(object): pass r = R() s = JObject(r) # Check if Java will be able to work with this object safely self.assertTrue(s.equals(s)) self.assertIsInstance(s.getClass(), java.lang.Class) self.assertIsInstance(s.toString(), java.lang.String) self.assertIsInstance(s.hashCode(), int) def testMethods2(self): fixture = JClass("jpype.common.Fixture")() class R(object): pass r = JProxy("java.io.Serializable", inst=R()) s = JObject(r) # Check if Java will be able to work with this object safely self.assertTrue(s.equals(s)) self.assertIsInstance(s.getClass(), java.lang.Class) self.assertIsInstance(s.toString(), java.lang.String) self.assertIsInstance(s.hashCode(), int) def testDeferredCheckingFailure(self): @JImplements("java.lang.Runnable", deferred=True) class MyImpl(object): pass with self.assertRaisesRegex(NotImplementedError, "requires method"): MyImpl() def testDeferredCheckingValid(self): @JImplements("java.lang.Runnable", deferred=True) class MyImpl(object): @JOverride def run(self): pass assert isinstance(MyImpl(), MyImpl) def testWeak(self): hc = java.lang.System.identityHashCode @JImplements("java.io.Serializable") class MyObj(object): pass def f(): obj = MyObj() jobj = JObject(obj) i = hc(obj) return i, obj i0, obj = f() i1 = hc(obj) # These should be the same if unless the reference was broken self.assertEqual(i0, i1) def testFunctional(self): def SupplierFunc(): return 561 js = JObject(SupplierFunc, "java.util.function.Supplier") self.assertEqual(js.get(), 561) def testFunctionalLambda(self): js = JObject(lambda x: 2 * x, "java.util.function.DoubleUnaryOperator") self.assertEqual(js.applyAsDouble(1), 2.0) @subrun.TestCase(individual=True) class TestProxyDefinitionWithoutJVM(common.JPypeTestCase): def setUp(self): # Explicitly *don't* call the parent setUp as this would start the JVM. pass @contextlib.contextmanager def assertRaisesJVMNotRunning(self): with self.assertRaisesRegex( RuntimeError, "Java Virtual Machine is not running"): yield def testDeferredCheckingNeedsJVM(self): @JImplements("java.lang.Runnable", deferred=True) class MyImpl(object): pass with self.assertRaisesJVMNotRunning(): MyImpl() def testNotDeferredChecking(self): with self.assertRaisesJVMNotRunning(): @JImplements("java.lang.Runnable", deferred=False) class MyImpl(object): pass def testDeferredDefault(self): with self.assertRaisesJVMNotRunning(): @JImplements("java.lang.Runnable") class MyImpl(object): pass def testValidDeferredJVMNotRunning(self): @JImplements("java.lang.Runnable", deferred=True) class MyImpl(object): @JOverride def run(self): pass with self.assertRaisesJVMNotRunning(): MyImpl() def testValidDeferredJVMRunning(self): @JImplements("java.lang.Runnable", deferred=True) class MyImpl(object): @JOverride def run(self): pass startJVM() assert isinstance(MyImpl(), MyImpl) jpype-1.3.0/test/jpypetest/test_proxy_multithreaded.py000066400000000000000000000113321405671516700233710ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** from jpype import * import common import time class C: def testMethodInt(self): return 5 def testMethodObject(self): return JPackage("jpype.proxy").ReturnObject(3) def testMethodString(self): return "Hallo" def testMethodList(self, noOfValues): responses = list() for i in range(0, noOfValues): responses.append(JPackage("jpype.proxy").ReturnObject(i)) return java.util.Arrays.asList(responses) class ThreadCallbackImpl: def __init__(self): self.values = [] def notifyValue(self, val): self.values.append(val) class ProxyMultiThreadedTestCase(common.JPypeTestCase): def setUp(self): super(ProxyMultiThreadedTestCase, self).setUp() self.package = JPackage("jpype.proxy") self.executor = None def tearDown(self): if self.executor is not None: self.executor.shutdown() def testProxyWithSingleThreadExecution(self): """Test multiple proxy calls with a single threaded executor. The Java part will only call one proxy method (longer running methods) at a time. The methods should run correctly. """ proxy = JProxy(self.package.TestInterface4, inst=C()) self.executor = self.package.ProxyExecutor(1) self.executor.registerProxy(proxy, 10) # register proxy executions # threads self.executor.runExecutor() result = self.executor.waitForExecutedTasks() expected = self.executor.getExpectedTasks() self.assertEqual(result, expected, "Executed Tasks should be the same.") def testProxyWithMultipleThreadExecutionSingleCallbackInstance(self): """Test multiple proxy calls with different threads at the same time. The Java part will call the same callback instance from different threads at a time. Jpype library will throw an exception and the proxy method won't be called: java.lang.RuntimeException: Python exception thrown: AttributeError: 'NoneType' object has no attribute 'getName' at jpype.JPypeInvocationHandler.hostInvoke(Native Method) at jpype.JPypeInvocationHandler.invoke( JPypeInvocationHandler.java:10) ... """ proxy = JProxy(self.package.TestInterface4, inst=C()) self.executor = self.package.ProxyExecutor(10) self.executor.registerProxy(proxy, 100) # register proxy executions # threads self.executor.runExecutor() result = self.executor.waitForExecutedTasks() expected = self.executor.getExpectedTasks() self.assertEqual(result, expected, "Executed Tasks should be the same.") def testProxyWithMultipleThreadExecutionMultiCallbackInstances(self): """Test multiple proxy calls with different threads at the same time. The Java part will call the proxy method from different callback instances and from different threads at a time. Jpype library will throw an exception and the proxy method won't be called: java.lang.RuntimeException: Python exception thrown: AttributeError: 'NoneType' object has no attribute 'getName' at jpype.JPypeInvocationHandler.hostInvoke(Native Method) at jpype.JPypeInvocationHandler.invoke( JPypeInvocationHandler.java:10) ... """ self.executor = self.package.ProxyExecutor(10) for i in range(0, 5): proxy = JProxy(self.package.TestInterface4, inst=C()) self.executor.registerProxy(proxy, 15) # register proxy executions # threads self.executor.runExecutor() result = self.executor.waitForExecutedTasks() expected = self.executor.getExpectedTasks() self.assertEqual(result, expected, "Executed Tasks should be the same.") jpype-1.3.0/test/jpypetest/test_ref.py000066400000000000000000000043551405671516700200600ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import sys import _jpype import jpype from jpype import JImplements, JOverride from jpype.types import * import common class ReferenceQueueTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) self.refqueue = jpype.JClass( 'org.jpype.ref.JPypeReferenceQueue').getInstance() def testAccess(self): # Make sure we can get the instance self.assertTrue(self.refqueue != None) def testRunning(self): # Get the queue instance self.assertTrue(self.refqueue.isRunning()) def testRefs(self): # This routine will exercise each of the clean up paths once fixture = JClass("jpype.common.Fixture")() def f(): # Create a proxy to test the proxy path @JImplements("java.util.function.Supplier") class MySupplier(object): @JOverride def get(self): # Send a Python exc to trigger Python ref path raise RuntimeError("foo") try: u = MySupplier() fixture.callSupplier(u) except RuntimeError as ex: pass f() # Force a direct byffer and then trash it b = bytearray([1, 2, 3]) _jpype.convertToDirectBuffer(b) # Then force a GC to clean it up jpype.java.lang.System.gc() # We can't check the results here as the GC may chose not # to run which would trigger a failure jpype-1.3.0/test/jpypetest/test_reflect.py000066400000000000000000000055611405671516700207300ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import sys import jpype from jpype import JPackage, JArray, JByte, java import common class ReflectCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) self.test1 = jpype.JClass('jpype.overloads.Test1')() self.Reflect = jpype.JClass('jpype.reflect.ReflectionTest') self.Annotation = jpype.JClass('jpype.reflect.Annotation') def testClass(self): t = jpype.JClass('java.lang.Object') obj = self.Reflect() self.assertEqual('Class', self.test1.testClassVsObject(self.Reflect)) self.assertEqual( 'Class', self.test1.testClassVsObject(self.Reflect.class_)) self.assertEqual( 'Class', self.test1.testClassVsObject(obj.getClass())) self.assertEqual( 'Class', self.test1.testClassVsObject(obj.__class__.class_)) def testAnnotation(self): method = self.Reflect.class_.getMethod('annotatedMethod') annotation = method.getAnnotation(self.Annotation) self.assertEqual('annotation', annotation.value()) def testCallPublicMethod(self): method = self.Reflect.class_.getMethod('publicMethod') obj = self.Reflect() self.assertIsNotNone(obj) self.assertIsNotNone(method) self.assertEqual('public', method.invoke(obj)) def testCallPrivateMethod(self): method = self.Reflect.class_.getDeclaredMethod('privateMethod') method.setAccessible(True) obj = self.Reflect() self.assertIsNotNone(obj) self.assertIsNotNone(method) self.assertEqual('private', method.invoke(obj)) def testAccessPublicField(self): field = self.Reflect.class_.getField('publicField') obj = self.Reflect() self.assertIsNotNone(obj) self.assertIsNotNone(field) self.assertEqual('public', field.get(obj)) def testAccessPrivateField(self): field = self.Reflect.class_.getDeclaredField('privateField') obj = self.Reflect() field.setAccessible(True) self.assertIsNotNone(obj) self.assertIsNotNone(field) self.assertEqual('private', field.get(obj)) jpype-1.3.0/test/jpypetest/test_repr.py000066400000000000000000000040341405671516700202460ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import jpype from jpype.types import * from jpype import JPackage, java import common class ReprTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) def testClass(self): cls = JClass("java.lang.String") self.assertIsInstance(str(cls), str) self.assertIsInstance(repr(cls), str) def testMethod(self): JS = JClass("java.lang.String") method = JS.substring self.assertIsInstance(str(method), str) self.assertIsInstance(repr(method), str) def testField(self): JS = JClass("java.lang.String") field = JS.__dict__['CASE_INSENSITIVE_ORDER'] self.assertIsInstance(str(JS.substring), str) self.assertIsInstance(repr(JS.substring), str) def testMonitor(self): JI = JClass("java.lang.Integer") with jpype.synchronized(JI) as monitor: self.assertIsInstance(str(monitor), str) self.assertIsInstance(repr(monitor), str) def testArray(self): array = JArray(JInt)([1, 2, 3]) self.assertIsInstance(str(array), str) self.assertIsInstance(repr(array), str) def testObject(self): obj = JObject("abc", JObject) self.assertIsInstance(str(obj), str) self.assertIsInstance(repr(obj), str) jpype-1.3.0/test/jpypetest/test_serial.py000066400000000000000000000032401405671516700205530ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** from jpype import JException, java, JProxy, JClass import os import sys import tempfile import traceback import common class SerializationTestCase(common.JPypeTestCase): def setUp(self): super(SerializationTestCase, self).setUp() self.tempname = tempfile.mktemp() def tearDown(self): os.remove(self.tempname) def testSerialize(self): o = JClass("jpype.serial.SerializationTest")() tmp = self.tempname fos = java.io.FileOutputStream(tmp) oos = java.io.ObjectOutputStream(fos) oos.writeObject(o) oos.flush() oos.close() fos.close() # The following cannto work because JPype has no way to simulate the "caller's ClassLoader" # def testDeSerialize(self): # fis = java.io.FileInputStream(self.tempname) # ois = java.io.ObjectInputStream(fis) # # o = ois.readObject() # ois.close() # fis.close() jpype-1.3.0/test/jpypetest/test_shutdown.py000066400000000000000000000046371405671516700211620ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import unittest import jpype import subrun @subrun.TestCase class ShutdownTest(unittest.TestCase): @classmethod def setUpClass(cls): jpype.startJVM(convertStrings=False) # Create some resources cls.jstr = jpype.java.lang.String("good morning") cls.jobj = jpype.java.lang.Object() cls.jcls = jpype.JClass("java.lang.String") cls.jarray = jpype.JArray(jpype.JInt)([1, 2, 3, 4]) # Then blow everything up jpype.shutdownJVM() def testArrayGet(self): with self.assertRaises(jpype.JVMNotRunning): type(self).jarray[0] def testArraySet(self): with self.assertRaises(jpype.JVMNotRunning): type(self).jarray[0] = 1 def testArrayGetSlice(self): with self.assertRaises(jpype.JVMNotRunning): type(self).jarray[0:2] def testArraySetSlice(self): with self.assertRaises(jpype.JVMNotRunning): type(self).jarray[0:2] = [1, 2] def testArrayStr(self): with self.assertRaises(jpype.JVMNotRunning): str(type(self).jarray) def testClassCtor(self): with self.assertRaises(jpype.JVMNotRunning): obj = type(self).jcls() def testObjectInvoke(self): with self.assertRaises(jpype.JVMNotRunning): type(self).jobj.wait() def testObjectStr(self): with self.assertRaises(jpype.JVMNotRunning): str(type(self).jobj) def testStringInvoke(self): with self.assertRaises(jpype.JVMNotRunning): type(self).jstr.substring(1) def testStringStr(self): with self.assertRaises(jpype.JVMNotRunning): str(type(self).jstr) jpype-1.3.0/test/jpypetest/test_sql_generic.py000066400000000000000000000104041405671516700215670ustar00rootroot00000000000000# This file is Public Domain and may be used without restrictions. import _jpype import jpype from jpype.types import * from jpype import java import jpype.dbapi2 as dbapi2 import common import time try: import zlib except ImportError: zlib = None class SQLModuleTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) def assertIsSubclass(self, a, b): self.assertTrue(issubclass(a, b), "`%s` is not a subclass of `%s`" % (a.__name__, b.__name__)) def testConstants(self): self.assertEqual(dbapi2.apilevel, "2.0") self.assertEqual(dbapi2.threadsafety, 2) self.assertEqual(dbapi2.paramstyle, "qmark") def testExceptions(self): self.assertIsSubclass(dbapi2.Warning, Exception) self.assertIsSubclass(dbapi2.Error, Exception) self.assertIsSubclass(dbapi2.InterfaceError, dbapi2.Error) self.assertIsSubclass(dbapi2.DatabaseError, dbapi2.Error) self.assertIsSubclass(dbapi2._SQLException, dbapi2.Error) self.assertIsSubclass(dbapi2.DataError, dbapi2.DatabaseError) self.assertIsSubclass(dbapi2.OperationalError, dbapi2.DatabaseError) self.assertIsSubclass(dbapi2.IntegrityError, dbapi2.DatabaseError) self.assertIsSubclass(dbapi2.InternalError, dbapi2.DatabaseError) self.assertIsSubclass(dbapi2.InternalError, dbapi2.DatabaseError) self.assertIsSubclass(dbapi2.ProgrammingError, dbapi2.DatabaseError) self.assertIsSubclass(dbapi2.NotSupportedError, dbapi2.DatabaseError) def testConnectionExceptions(self): cx = dbapi2.Connection self.assertEqual(cx.Warning, dbapi2.Warning) self.assertEqual(cx.Error, dbapi2.Error) self.assertEqual(cx.InterfaceError, dbapi2.InterfaceError) self.assertEqual(cx.DatabaseError, dbapi2.DatabaseError) self.assertEqual(cx.DataError, dbapi2.DataError) self.assertEqual(cx.OperationalError, dbapi2.OperationalError) self.assertEqual(cx.IntegrityError, dbapi2.IntegrityError) self.assertEqual(cx.InternalError, dbapi2.InternalError) self.assertEqual(cx.InternalError, dbapi2.InternalError) self.assertEqual(cx.ProgrammingError, dbapi2.ProgrammingError) self.assertEqual(cx.NotSupportedError, dbapi2.NotSupportedError) def test_Date(self): d1 = dbapi2.Date(2002, 12, 25) # noqa F841 d2 = dbapi2.DateFromTicks( # noqa F841 time.mktime((2002, 12, 25, 0, 0, 0, 0, 0, 0)) ) # Can we assume this? API doesn't specify, but it seems implied # self.assertEqual(str(d1),str(d2)) def test_Time(self): t1 = dbapi2.Time(13, 45, 30) # noqa F841 t2 = dbapi2.TimeFromTicks( # noqa F841 time.mktime((2001, 1, 1, 13, 45, 30, 0, 0, 0)) ) # Can we assume this? API doesn't specify, but it seems implied # self.assertEqual(str(t1),str(t2)) def test_Timestamp(self): t1 = dbapi2.Timestamp(2002, 12, 25, 13, 45, 30) # noqa F841 t2 = dbapi2.TimestampFromTicks( # noqa F841 time.mktime((2002, 12, 25, 13, 45, 30, 0, 0, 0)) ) # Can we assume this? API doesn't specify, but it seems implied # self.assertEqual(str(t1),str(t2)) def test_Binary(self): b = dbapi2.Binary(b"Something") b = dbapi2.Binary(b"") # noqa F841 def test_STRING(self): self.assertTrue(hasattr(dbapi2, "STRING"), "module.STRING must be defined") def test_BINARY(self): self.assertTrue( hasattr(dbapi2, "BINARY"), "module.BINARY must be defined." ) def test_NUMBER(self): self.assertTrue( hasattr(dbapi2, "NUMBER"), "module.NUMBER must be defined." ) def test_DATETIME(self): self.assertTrue( hasattr(dbapi2, "DATETIME"), "module.DATETIME must be defined." ) def test_ROWID(self): self.assertTrue(hasattr(dbapi2, "ROWID"), "module.ROWID must be defined.") class SQLTablesTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) def testStr(self): for i in dbapi2._types: self.assertIsInstance(str(i), str) def testRepr(self): for i in dbapi2._types: self.assertIsInstance(repr(i), str) jpype-1.3.0/test/jpypetest/test_sql_h2.py000066400000000000000000001534171405671516700205000ustar00rootroot00000000000000# This file is Public Domain and may be used without restrictions, # because noone should have to waste their lives typing this again. import _jpype import jpype from jpype.types import * from jpype import java import jpype.dbapi2 as dbapi2 import common import time import datetime import decimal import threading java = jpype.java try: import zlib except ImportError: zlib = None db_name = "jdbc:h2:mem:testdb" class ConnectTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) if common.fast: raise common.unittest.SkipTest("fast") def testConnect(self): cx = dbapi2.connect(db_name) self.assertIsInstance(cx, dbapi2.Connection) def testClose(self): cx = dbapi2.connect(db_name) cx.close() # Closing twice is an error with self.assertRaises(dbapi2.ProgrammingError): cx.close() def testScope(self): with dbapi2.connect(db_name) as cx: pass with self.assertRaises(dbapi2.ProgrammingError): cx.close() def testAdapters(self): cx = dbapi2.connect(db_name) self.assertEqual(cx.adapters, dbapi2._default_adapters) cx = dbapi2.connect(db_name, adapters=None) self.assertEqual(cx.adapters, {}) m = {} cx = dbapi2.connect(db_name, adapters=m) self.assertEqual(cx.adapters, m) def testConverters(self): cx = dbapi2.connect(db_name) self.assertEqual(cx.converters, dbapi2._default_converters) cx = dbapi2.connect(db_name, converters=None) self.assertEqual(cx.converters, {}) m = {} cx = dbapi2.connect(db_name, converters=m) self.assertEqual(cx.converters, m) class ConnectionTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) if common.fast: raise common.unittest.SkipTest("fast") def test_commit(self): with dbapi2.connect(db_name) as cx: # Commit must work without a command cx.commit() def test_rollback(self): with dbapi2.connect(db_name) as cx: # Commit must work without a command cx.rollback() def test_cursor(self): with dbapi2.connect(db_name) as cx: self.assertIsInstance(cx.cursor(), dbapi2.Cursor) def testAdapters(self): with dbapi2.connect(db_name) as cx: m = {'foo': 1} cx.adapters = m self.assertEqual(cx._adapters, m) with self.assertRaises(TypeError): cx.adapters = object() def testConverters(self): with dbapi2.connect(db_name) as cx: m = {'foo': 1} cx.converters = m self.assertEqual(cx._converters, m) with self.assertRaises(TypeError): cx.converters = object() def testClosedClass(self): with dbapi2.connect(db_name) as cx: with self.assertRaises(AttributeError): cx.seters = object() def testAutocommitFail(self): with dbapi2.connect(db_name) as cx: cx.autocommit = True with self.assertRaises(dbapi2.NotSupportedError): cx.commit() with self.assertRaises(dbapi2.NotSupportedError): cx.rollback() def test_typeinfo(self): with dbapi2.connect(db_name) as cx: ti = cx.typeinfo self.assertIsInstance(ti, dict) for p, v in ti.items(): self.assertIsInstance(p, str) self.assertIsInstance(v, dbapi2.JDBCType) with self.assertRaises(dbapi2.ProgrammingError): ti = cx.typeinfo def test_connection(self): with dbapi2.connect(db_name) as cx: c = cx.connection self.assertIsInstance(c, java.sql.Connection) def test_getters(self): with dbapi2.connect(db_name) as cx: cx.getters = dbapi2.GETTERS_BY_NAME self.assertEqual(cx._getters, dbapi2.GETTERS_BY_NAME) self.assertEqual(cx.getters, dbapi2.GETTERS_BY_NAME) cx.getters = dbapi2.GETTERS_BY_TYPE self.assertEqual(cx._getters, dbapi2.GETTERS_BY_TYPE) self.assertEqual(cx.getters, dbapi2.GETTERS_BY_TYPE) def test_setters(self): with dbapi2.connect(db_name) as cx: cx.setters = dbapi2.SETTERS_BY_META self.assertEqual(cx._setters, dbapi2.SETTERS_BY_META) self.assertEqual(cx.setters, dbapi2.SETTERS_BY_META) cx.setters = dbapi2.SETTERS_BY_TYPE self.assertEqual(cx._setters, dbapi2.SETTERS_BY_TYPE) self.assertEqual(cx.setters, dbapi2.SETTERS_BY_TYPE) def test_adapters(self): with dbapi2.connect(db_name) as cx: self.assertEqual(cx.adapters, dbapi2._default_adapters) cx.adapters = None self.assertEqual(cx.adapters, {}) m = {} cx.adapters = m self.assertEqual(cx.adapters, m) with self.assertRaises(dbapi2.InterfaceError): cx.adapters = object() def test_converters(self): with dbapi2.connect(db_name) as cx: self.assertEqual(cx.converters, dbapi2._default_converters) cx.converters = None self.assertEqual(cx.converters, {}) m = {} cx.converters = m self.assertEqual(cx.converters, m) with self.assertRaises(dbapi2.InterfaceError): cx.converters = object() class CursorTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) if common.fast: raise common.unittest.SkipTest("fast") def tearDown(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: try: cur.execute("drop table booze") except dbapi2.Error: pass try: cur.execute("drop table barflys") except dbapi2.Error: pass def testCursorIsolation(self): with dbapi2.connect(db_name) as cx: # Make sure cursors created from the same connection have # the documented transaction isolation level cur1 = cx.cursor() cur2 = cx.cursor() cur1.execute("create table booze (name varchar(20))") cur1.execute("insert into booze values ('Victoria Bitter')") cur2.execute("select name from booze") booze = cur2.fetchall() self.assertEqual(len(booze), 1) self.assertEqual(len(booze[0]), 1) self.assertEqual(booze[0][0], "Victoria Bitter") def testDescription(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: cur.execute("create table booze (name varchar(20))") self.assertEqual( cur.description, None, "cursor.description should be none after executing a " "statement that can return no rows (such as create table)", ) cur.execute("select name from booze") self.assertEqual( len(cur.description), 1, "cursor.description describes too many columns" ) self.assertEqual( len(cur.description[0]), 7, "cursor.description[x] tuples must have 7 elements", ) self.assertEqual( cur.description[0][0].lower(), "name", "cursor.description[x][0] must return column name", ) self.assertEqual( cur.description[0][1], dbapi2.STRING, "cursor.description[x][1] must return column type. Got %r" % cur.description[0][1], ) # Make sure self.description gets reset cur.execute("create table barflys (name varchar(20))") self.assertEqual( cur.description, None, "cursor.description not being set to None when executing " "no-result statements (eg. create table)", ) def testRowcount(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: cur.execute("create table booze (name varchar(20))") # This was dropped from the specification # self.assertEqual( # cur.rowcount, # -1, # "cursor.rowcount should be -1 after executing no-result " "statements", # ) cur.execute("insert into booze values ('Victoria Bitter')") self.assertEqual( cur.rowcount, 1, "cursor.rowcount should == number or rows inserted, or " "set to -1 after executing an insert statement", ) cur.execute("select name from booze") self.assertEqual( cur.rowcount, -1, "cursor.rowcount should == number of rows returned, or " "set to -1 after executing a select statement", ) cur.execute("create table barflys (name varchar(20))") # THis test does not match jdbc parameters # self.assertEqual( # cur.rowcount, # -1, # "cursor.rowcount not being reset to -1 after executing " # "no-result statements", # ) def testClose(self): cx = dbapi2.connect(db_name) try: cur = cx.cursor() finally: cx.close() # cursor.execute should raise an Error if called after connection # closed with self.assertRaises(dbapi2.Error): cur.execute("create table booze (name varchar(20))") # connection.commit should raise an Error if called after connection' # closed.' self.assertRaises(dbapi2.Error, cx.commit) # connection.close should raise an Error if called more than once self.assertRaises(dbapi2.Error, cx.close) def test_None(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: cur.execute("create table booze (name varchar(20))") cur.execute("insert into booze values (NULL)") cur.execute("select name from booze") r = cur.fetchall() self.assertEqual(len(r), 1) self.assertEqual(len(r[0]), 1) self.assertEqual(r[0][0], None, "NULL value not returned as None") def testArraysize(self): # Not much here - rest of the tests for this are in test_fetchmany with dbapi2.connect(db_name) as cx, cx.cursor() as cur: self.assertTrue( hasattr(cur, "arraysize"), "cursor.arraysize must be defined" ) def _paraminsert(self, cur): cur.execute("create table booze (name varchar(20))") cur.execute("insert into booze values ('Victoria Bitter')") self.assertTrue(cur.rowcount in (-1, 1)) cur.execute("insert into booze values (?)", ("Cooper's",)) self.assertTrue(cur.rowcount in (-1, 1)) cur.execute("select name from booze") res = cur.fetchall() self.assertEqual(len(res), 2, "cursor.fetchall returned too few rows") beers = [res[0][0], res[1][0]] beers.sort() self.assertEqual( beers[0], "Cooper's", "cursor.fetchall retrieved incorrect data, or data inserted " "incorrectly", ) self.assertEqual( beers[1], "Victoria Bitter", "cursor.fetchall retrieved incorrect data, or data inserted " "incorrectly", ) def test_execute(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: self._paraminsert(cur) def test_executeBad(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: with self.assertRaises(dbapi2.InterfaceError): cur.execute("insert into booze values (?)", object()) with self.assertRaises(dbapi2.InterfaceError): cur.execute(object()) with self.assertRaises(dbapi2.ProgrammingError): cur.execute("inert into booze values (?)", [["?"]]) def test_setinputsizes(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: cur.setinputsizes((25,)) self._paraminsert(cur) # Make sure cursor still works def test_setoutputsize_basic(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: cur.setoutputsize(1000) cur.setoutputsize(2000, 0) self._paraminsert(cur) # Make sure the cursor still works def test_executemany(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: cur.execute("create table booze (name varchar(20))") largs = [("Cooper's",), ("Boag's",)] margs = [{"beer": "Cooper's"}, {"beer": "Boag's"}] cur.executemany("insert into booze values (?)", largs) self.assertEqual( cur.rowcount, 2, "insert using cursor.executemany set cursor.rowcount to " "incorrect value %r" % cur.rowcount, ) cur.execute("select name from booze") res = cur.fetchall() self.assertEqual( len(res), 2, "cursor.fetchall retrieved incorrect number of rows" ) beers = [res[0][0], res[1][0]] beers.sort() self.assertEqual(beers[0], "Boag's", "incorrect data retrieved") self.assertEqual(beers[1], "Cooper's", "incorrect data retrieved") def test_executemanyGenerator(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: def mygen(ls): for i in ls: yield [i] cu.execute("create table booze (name varchar(20))") cu.executemany("insert into booze values (?)", mygen(self.samples)) cu.execute("select * from booze") f = cu.fetchall() for i, v in enumerate(self.samples): self.assertEqual(f[i][0], v) def test_executemanyIterator(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: class myiter: def __init__(self, ls): self.ls = ls self.i = 0 def __iter__(self): return self def __next__(self): if self.i == len(self.ls): raise StopIteration rc = [self.ls[self.i]] self.i += 1 return rc cu.execute("create table booze (name varchar(20))") cu.executemany("insert into booze values (?)", myiter(self.samples)) cu.execute("select * from booze") f = cu.fetchall() for i, v in enumerate(self.samples): self.assertEqual(f[i][0], v) def test_executemanyBad(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table booze (name varchar(20))") with self.assertRaises(TypeError): cu.executemany("insert into booze values (?)", object()) with self.assertRaises(dbapi2.InterfaceError): cu.executemany("insert into booze values (?)", object()) with self.assertRaises(dbapi2.InterfaceError): cu.executemany(object(), []) cu.executemany("insert into booze values (?)", None) with self.assertRaises(dbapi2.ProgrammingError): cu.executemany("inert into booze values (?)", [['?']]) def test_fetchone(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: # cursor.fetchone should raise an Error if called before # executing a select-type query self.assertRaises(dbapi2.ProgrammingError, cur.fetchone) # cursor.fetchone should raise an Error if called after # executing a query that cannot return rows cur.execute("create table booze (name varchar(20))") self.assertRaises(dbapi2.Error, cur.fetchone) cur.execute("select name from booze") self.assertEqual( cur.fetchone(), None, "cursor.fetchone should return None if a query retrieves " "no rows", ) self.assertEqual(cur.rowcount, -1) # cursor.fetchone should raise an Error if called after # executing a query that cannot return rows cur.execute("insert into booze values ('Victoria Bitter')") self.assertRaises(dbapi2.Error, cur.fetchone) cur.execute("select name from booze") r = cur.fetchone() self.assertEqual( len(r), 1, "cursor.fetchone should have retrieved a single row" ) self.assertEqual( r[0], "Victoria Bitter", "cursor.fetchone retrieved incorrect data" ) self.assertEqual( cur.fetchone(), None, "cursor.fetchone should return None if no more rows available", ) self.assertEqual(cur.rowcount, -1) samples = [ "Carlton Cold", "Carlton Draft", "Mountain Goat", "Redback", "Victoria Bitter", "XXXX", ] def _populate(self): """ Return a list of sql commands to setup the DB for the fetch tests. """ populate = [ "insert into booze values ('{}')".format(s) for s in self.samples ] return populate def test_fetchmany(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: # cursor.fetchmany should raise an Error if called without # issuing a query self.assertRaises(dbapi2.ProgrammingError, cur.fetchmany, 4) cur.execute("create table booze (name varchar(20))") for sql in self._populate(): cur.execute(sql) cur.execute("select name from booze") r = cur.fetchmany() self.assertEqual( len(r), 1, "cursor.fetchmany retrieved incorrect number of rows, " "default of arraysize is one.", ) cur.arraysize = 10 r = cur.fetchmany(3) # Should get 3 rows self.assertEqual( len(r), 3, "cursor.fetchmany retrieved incorrect number of rows" ) r = cur.fetchmany(4) # Should get 2 more self.assertEqual( len(r), 2, "cursor.fetchmany retrieved incorrect number of rows" ) r = cur.fetchmany(4) # Should be an empty sequence self.assertEqual( len(r), 0, "cursor.fetchmany should return an empty sequence after " "results are exhausted", ) self.assertEqual(cur.rowcount, -1) # Same as above, using cursor.arraysize cur.arraysize = 4 cur.execute("select name from booze") r = cur.fetchmany() # Should get 4 rows self.assertEqual( len(r), 4, "cursor.arraysize not being honoured by fetchmany" ) r = cur.fetchmany() # Should get 2 more self.assertEqual(len(r), 2) r = cur.fetchmany() # Should be an empty sequence self.assertEqual(len(r), 0) self.assertEqual(cur.rowcount, -1) cur.arraysize = 6 cur.execute("select name from booze") rows = cur.fetchmany() # Should get all rows self.assertTrue(cur.rowcount in (-1, 6)) self.assertEqual(len(rows), 6) self.assertEqual(len(rows), 6) rows = [r[0] for r in rows] rows.sort() # Make sure we get the right data back out for i in range(0, 6): self.assertEqual( rows[i], self.samples[i], "incorrect data retrieved by cursor.fetchmany", ) rows = cur.fetchmany() # Should return an empty list self.assertEqual( len(rows), 0, "cursor.fetchmany should return an empty sequence if " "called after the whole result set has been fetched", ) self.assertEqual(cur.rowcount, -1) cur.execute("create table barflys (name varchar(20))") cur.execute("select name from barflys") r = cur.fetchmany() # Should get empty sequence self.assertEqual( len(r), 0, "cursor.fetchmany should return an empty sequence if " "query retrieved no rows", ) def test_fetchall(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: # cursor.fetchall should raise an Error if called # without executing a query that may return rows (such # as a select) self.assertRaises(dbapi2.Error, cur.fetchall) cur.execute("create table booze (name varchar(20))") for sql in self._populate(): cur.execute(sql) # cursor.fetchall should raise an Error if called # after executing a statement that cannot return rows self.assertRaises(dbapi2.ProgrammingError, cur.fetchall) cur.execute("select name from booze") rows = cur.fetchall() self.assertEqual(cur.rowcount, -1) self.assertEqual( len(rows), len(self.samples), "cursor.fetchall did not retrieve all rows", ) rows = [r[0] for r in rows] rows.sort() for i in range(0, len(self.samples)): self.assertEqual( rows[i], self.samples[i], "cursor.fetchall retrieved incorrect rows" ) rows = cur.fetchall() self.assertEqual( len(rows), 0, "cursor.fetchall should return an empty list if called " "after the whole result set has been fetched", ) self.assertEqual(cur.rowcount, -1) cur.execute("create table barflys (name varchar(20))") cur.execute("select name from barflys") rows = cur.fetchall() self.assertEqual(cur.rowcount, -1) self.assertEqual( len(rows), 0, "cursor.fetchall should return an empty list if " "a select query returns no rows", ) def test_mixedfetch(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: cur.execute("create table booze (name varchar(20))") for sql in self._populate(): cur.execute(sql) cur.execute("select name from booze") self.assertEqual(cur.rowcount, -1) rows1 = cur.fetchone() rows23 = cur.fetchmany(2) rows4 = cur.fetchone() rows56 = cur.fetchall() self.assertEqual(cur.rowcount, -1) self.assertEqual( len(rows23), 2, "fetchmany returned incorrect number of rows" ) self.assertEqual( len(rows56), 2, "fetchall returned incorrect number of rows" ) rows = [rows1[0]] rows.extend([rows23[0][0], rows23[1][0]]) rows.append(rows4[0]) rows.extend([rows56[0][0], rows56[1][0]]) rows.sort() for i in range(0, len(self.samples)): self.assertEqual( rows[i], self.samples[i], "incorrect data retrieved or inserted" ) def test_nextset(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table booze (name varchar(20))") booze = ["Wiskey", ] cu.execute("insert into booze(name) values (?)", booze) self.assertEqual(cu.rowcount, 1) cu.execute("select * from booze; select * from booze") self.assertEqual(cu.fetchone(), booze) nxt = cu.nextset() self.assertTrue(nxt in (True, None)) # H2 does not support multiple result sets if nxt: self.assertEqual(cu.fetchone(), booze) def test_lastrowid(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table booze(id identity auto_increment not null, name varchar(255), PRIMARY KEY (id))") cu.execute("insert into booze(name) values('hello')", keys=True) id0 = cu.lastrowid self.assertIsInstance(id0, int) # Call more than once id1 = cu.lastrowid self.assertIsInstance(id1, int) cx.commit() cu.execute("insert into booze(name) values('there')", keys=True) id2 = cu.lastrowid self.assertIsInstance(id2, int) cu.execute("select * from booze") f = cu.fetchall() self.assertEqual(cu.lastrowid, None) self.assertEqual(f[0][0], id0) self.assertEqual(f[1][0], id2) def test_lastrowidMany(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table booze(id identity auto_increment not null, name varchar(255), PRIMARY KEY (id))") cu.executemany("insert into booze(name) values(?)", [['Redback'], ['Fat Yak']], keys=True) ids = cu.lastrowid self.assertIsInstance(ids, list) self.assertEqual(len(ids), 2) cu.execute("select * from booze") f = cu.fetchall() self.assertEqual(f[0][0], ids[0]) self.assertEqual(f[1][0], ids[1]) def test_iter(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: ls = [['Tooheys Old'], ['Nine Tales Original Amber Ale'], ['Dogbolter']] cu.execute("create table booze(name varchar(255))") cu.executemany("insert into booze(name) values(?)", ls, keys=True) # make sure we throw if there is no result set with self.assertRaises(dbapi2.ProgrammingError): for booze in cu: pass cu.execute("select * from booze") for i, booze in enumerate(cu): self.assertEqual(ls[i], booze) def testNoAdapter(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table booze(name varchar(50))") with self.assertRaises(dbapi2.InterfaceError): cu.execute("insert into booze(name) values(?)", [object()]) def testBadParameters(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table booze(name varchar(50))") with self.assertRaises(dbapi2.InterfaceError): cu.execute("insert into booze(name) values(?)", object()) def test_callproc(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: r = cu.callproc("lower", ("FOO",)) self.assertEqual(len(r), 1) self.assertEqual(r[0], "FOO") r = cu.fetchall() self.assertEqual(len(r), 1) self.assertEqual(len(r[0]), 1) self.assertEqual(r[0][0], "foo") def test_callprocBad(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: with self.assertRaises(dbapi2.ProgrammingError): r = cu.callproc("not_there", ("FOO",)) with self.assertRaises(dbapi2.InterfaceError): r = cu.callproc(object(), ("FOO",)) with self.assertRaises(dbapi2.InterfaceError): r = cu.callproc("lower", (object(),)) with self.assertRaises(dbapi2.InterfaceError): r = cu.callproc("lower", object()) def test_close(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.close() with self.assertRaises(dbapi2.ProgrammingError): cu.close() def test_parameters(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: with self.assertRaises(dbapi2.ProgrammingError): p = cu.parameters cu.execute("create table booze(name varchar(50))") cu.execute("insert into booze(name) values(?)", ('Hahn Super Dry',)) p = cu.parameters self.assertEqual(p[0][0:2], ('VARCHAR', dbapi2.VARCHAR)) def test_resultSet(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table booze(name varchar(50))") cu.execute("insert into booze(name) values(?)", ('Hahn Super Dry',)) cu.execute("select * from booze") rs = cu.resultSet self.assertIsInstance(rs, java.sql.ResultSet) def test_fetchClosed(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table booze(name varchar(50))") cu.execute("insert into booze(name) values(?)", ('Hahn Super Dry',)) cu.execute("select * from booze") cu.close() with self.assertRaises(dbapi2.ProgrammingError): cu.fetchone() with self.assertRaises(dbapi2.ProgrammingError): cu.fetchmany() with self.assertRaises(dbapi2.ProgrammingError): cu.fetchall() self.assertEqual(cu.resultSet, None) def test_executeBadParameters(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: def mygen(ls): for i in ls: yield i cu.execute("create table booze(name varchar(50), price integer)") with self.assertRaises(dbapi2.ProgrammingError): cu.executemany("insert into booze(name,price) values(?,?)", [('Hahn Super Dry', 2), ('Coors',)]) with self.assertRaises(dbapi2.InterfaceError): cu.execute("insert into booze(name,price) values(?,?)", {'name': 'Budweiser', 'price': 10}) with self.assertRaises(dbapi2.ProgrammingError): cu.executemany("insert into booze(name,price) values(?,?)", mygen([['Budweiser']])) cu.execute("insert into booze(name,price) values(?,?)", mygen(['Pabst Blue Robot', 20000])) with self.assertRaises(dbapi2.ProgrammingError): cu.execute("insert into booze(name,price) values(?,?)", mygen(['Budweiser'])) with self.assertRaises(dbapi2.InterfaceError): cu.execute("insert into booze(name,price) values(?,?)", 'Budweiser') with self.assertRaises(dbapi2.ProgrammingError): cu.execute("insert into booze(name,price) values(?,?)", mygen(['Budweiser', 2, 'no'])) with self.assertRaises(dbapi2.InterfaceError): cu.execute("insert into booze(name,price) values(?,?)", object()) class AdapterTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) if common.fast: raise common.unittest.SkipTest("fast") self.testdata = b"abcdefg" * 10 self.params = memoryview(zlib.compress(self.testdata)) def tearDown(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: try: cur.execute("drop table test") except dbapi2.Error: pass def testOnConnector(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name varchar(255))") cx.adapters[object] = lambda x: "none" cu.execute("insert into test(name) values(?)", [object()]) cu.execute("select * from test") f = cu.fetchall() self.assertEqual(f[0][0], "none") @common.unittest.skipUnless(zlib, "requires zlib") class ConverterTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) if common.fast: raise common.unittest.SkipTest("fast") self.testdata = b"abcdefg" * 10 self.params = memoryview(zlib.compress(self.testdata)) def tearDown(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: try: cur.execute("drop table test") except dbapi2.Error: pass @staticmethod def convert(s): return zlib.decompress(s) def testConvertersBad(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name varchar(20))") cu.executemany("insert into test(name) values(?)", [['alice'], ['bob'], ['charlie']]) cu.execute("select name from test") with self.assertRaises(dbapi2.ProgrammingError): cu.fetchone(converters=[]) cu.execute("select name from test") with self.assertRaises(dbapi2.InterfaceError): cu.fetchone(converters=[int]) cu.execute("select name from test") with self.assertRaises(dbapi2.ProgrammingError): cu.fetchone(converters=[str, str]) def testConvertersNone(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name varchar(20))") cu.executemany("insert into test(name) values(?)", [['alice'], ['bob'], ['charlie']]) cu.execute("select name from test") f = cu.fetchone(converters=None) self.assertIsInstance(f[0], java.lang.String) cu.execute("select name from test") def testConvertersPositional(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name varchar(20))") cu.executemany("insert into test(name) values(?)", [['alice'], ['bob'], ['charlie']]) cu.execute("select name from test") f = cu.fetchone(converters=[str]) self.assertIsInstance(f[0], str) cu.execute("select name from test") def test_fetchoneTypesPositional(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name varchar(20))") cu.executemany("insert into test(name) values(?)", [['alice'], ['bob'], ['charlie']]) cu.execute("select name from test") f = cu.fetchone(types=[dbapi2.STRING]) self.assertIsInstance(f[0], str) def test_fetchmanyTypesPositional(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name varchar(20))") cu.executemany("insert into test(name) values(?)", [['alice'], ['bob'], ['charlie']]) cu.execute("select name from test") f = cu.fetchmany(types=[dbapi2.STRING]) self.assertIsInstance(f[0][0], str) def test_fetchallTypesPositional(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name varchar(20))") cu.executemany("insert into test(name) values(?)", [['alice'], ['bob'], ['charlie']]) cu.execute("select name from test") f = cu.fetchall(types=[dbapi2.STRING]) self.assertIsInstance(f[0][0], str) def testTypesPositionalBAD(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name varchar(20))") cu.executemany("insert into test(name) values(?)", [['alice'], ['bob'], ['charlie']]) cu.execute("select name from test") with self.assertRaises(dbapi2.ProgrammingError): f = cu.fetchone(types=[dbapi2.STRING, dbapi2.STRING]) with self.assertRaises(dbapi2.ProgrammingError): f = cu.fetchone(types=[]) class GettersTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) if common.fast: raise common.unittest.SkipTest("fast") self.testdata = b"abcdefg" * 10 self.params = memoryview(zlib.compress(self.testdata)) def tearDown(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: try: cur.execute("drop table test") except dbapi2.Error: pass class TransactionsTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) if common.fast: raise common.unittest.SkipTest("fast") def tearDown(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: try: cur.execute("drop table test") except dbapi2.Error: pass def testTransactionRollbackCreate(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cx.commit() # needed before starting transactions cu.execute("begin") cu.execute("create table test(name VARCHAR(10))") cx.rollback() # with self.assertRaises(dbapi2.ProgrammingError): cu.execute("select * from test") def testTransactionRollbackInsert(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cx.commit() # needed before starting transactions cu.execute("create table test(name VARCHAR(10))") cx.commit() cu.execute("begin") cu.execute("insert into test(name) values('alice')") cx.rollback() # Alice should go away result = cu.execute("select * from test").fetchall() self.assertEqual(result, []) def testTransactionRollbackClose(self): with dbapi2.connect(db_name) as cx2: with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cx.commit() # needed before starting transactions cu.execute("create table test(name VARCHAR(10))") cu.execute("insert into test(name) values('alice')") cx.commit() cu.execute("begin") cu.execute("insert into test(name) values('bob')") result = cu.execute("select * from test").fetchall() self.assertEqual(result, [['alice'], ['bob']]) # Bob should go away with cx2.cursor() as cu: result = cu.execute("select * from test").fetchall() self.assertEqual(result, [['alice']]) class TypeTestCase(common.JPypeTestCase): """ This test is db dependent, but needed to check all code paths. """ def setUp(self): common.JPypeTestCase.setUp(self) if common.fast: raise common.unittest.SkipTest("fast") def tearDown(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: try: cur.execute("drop table test") except dbapi2.Error: pass def testTime(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(NAME TIME)") cu.execute("select * from test") cu.execute("insert into test(NAME) values('12:05:10')") f = cu.execute('select * from test').fetchone() self.assertIsInstance(f[0], datetime.time) cu.execute("delete from test") cu.execute("insert into test(NAME) values(?)", f) f2 = cu.execute('select * from test').fetchone() self.assertEqual(f2, f) cu.execute("delete from test") # Test with Java t1 = jpype.java.sql.Time(1, 2, 3) cu.execute("insert into test(NAME) values(?)", [t1]) f3 = cu.execute('select * from test').fetchone() self.assertEqual(f3[0], datetime.time(1, 2, 3)) f4 = cu.execute('select * from test').fetchone(converters=None) self.assertEqual(f4[0], t1) self.assertIsInstance(f4[0], jpype.java.sql.Time) cu.execute("delete from test") # Test with dbapi2.Time t1 = dbapi2.Time(6, 21, 32) cu.execute("insert into test(NAME) values(?)", [t1]) f3 = cu.execute('select * from test').fetchone() self.assertEqual(f3[0], datetime.time(6, 21, 32)) def testDate(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(NAME DATE)") cu.execute("select * from test") cu.execute("insert into test(NAME) values('2012-02-05')") f = cu.execute('select * from test').fetchone() self.assertIsInstance(f[0], datetime.date) cu.execute("delete from test") cu.execute("insert into test(NAME) values(?)", f) f2 = cu.execute('select * from test').fetchone() self.assertEqual(f2, f) cu.execute("delete from test") # Test with Java t1 = java.sql.Date(1972 - 1900, 4 - 1, 1) cu.execute("insert into test(NAME) values(?)", [t1]) f3 = cu.execute('select * from test').fetchone() self.assertEqual(f3[0], datetime.date(1972, 4, 1)) f4 = cu.execute('select * from test').fetchone(converters=None) self.assertEqual(f4[0], t1) self.assertIsInstance(f4[0], java.sql.Date) cu.execute("delete from test") # Test with dbapi2.Date t1 = dbapi2.Date(2020, 5, 21) cu.execute("insert into test(NAME) values(?)", [t1]) f3 = cu.execute('select * from test').fetchone() self.assertEqual(f3[0], datetime.date(2020, 5, 21)) def testTimestamp(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(NAME TIMESTAMP)") cu.execute("select * from test") cu.execute("insert into test(NAME) values('2012-02-05 12:02:45.123')") f = cu.execute('select * from test').fetchone() self.assertIsInstance(f[0], datetime.date) cu.execute("delete from test") cu.execute("insert into test(NAME) values(?)", f) f2 = cu.execute('select * from test').fetchone() self.assertEqual(f2, f) cu.execute("delete from test") # Test with Java t1 = java.sql.Timestamp(1972 - 1900, 4 - 1, 1, 12, 2, 45, 123456000) cu.execute("insert into test(NAME) values(?)", [t1]) f3 = cu.execute('select * from test').fetchone() self.assertEqual(f3[0], datetime.datetime(1972, 4, 1, 12, 2, 45, 123456)) f4 = cu.execute('select * from test').fetchone(converters=None) self.assertEqual(f4[0], t1) self.assertIsInstance(f4[0], java.sql.Timestamp) cu.execute("delete from test") # Test with dbapi2.Date t1 = dbapi2.Timestamp(2020, 5, 21, 3, 4, 5, 123122000) cu.execute("insert into test(NAME) values(?)", [t1]) f3 = cu.execute('select * from test').fetchone() self.assertEqual(f3[0], datetime.datetime(2020, 5, 21, 3, 4, 5, 123122)) def _testInt(self, tp, desc, jtype, null=True): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(NAME %s)" % tp) cu.execute("insert into test(NAME) values(?)", [123]) f = cu.execute("select * from test").fetchone() self.assertEqual(f[0], 123) self.assertIsInstance(f[0], int) self.assertEqual(cu.description[0][0:2], desc) f = cu.execute("select * from test").fetchone(converters=None) self.assertEqual(f[0], 123) self.assertIsInstance(f[0], jtype) cu.execute("delete from test") if null: cu.execute("insert into test(NAME) values(?)", [None]) f = cu.execute("select * from test").fetchone(converters=None) self.assertEqual(f[0], None) def testTinyInt(self): self._testInt('TINYINT', ('NAME', 'TINYINT'), jpype.JShort) def testBigInt(self): self._testInt('BIGINT', ('NAME', 'BIGINT'), jpype.JLong) def testIdentity(self): self._testInt('IDENTITY', ('NAME', 'BIGINT'), jpype.JLong, False) def testInteger(self): self._testInt('INTEGER', ('NAME', 'INTEGER'), jpype.JInt) def testSmallInt(self): self._testInt('SMALLINT', ('NAME', 'SMALLINT'), jpype.JShort) def _testFloat(self, tp, desc, jtype): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(NAME %s)" % tp) cu.execute("insert into test(NAME) values(?)", [1.25]) f = cu.execute("select * from test").fetchone() self.assertEqual(f[0], 1.25) self.assertIsInstance(f[0], float) self.assertEqual(cu.description[0][0:2], desc) f = cu.execute("select * from test").fetchone(converters=None) self.assertEqual(f[0], 1.25) self.assertIsInstance(f[0], jtype) cu.execute("delete from test") cu.execute("insert into test(NAME) values(?)", [None]) f = cu.execute("select * from test").fetchone(converters=None) self.assertEqual(f[0], None) def testFloat(self): self._testFloat('FLOAT', ('NAME', 'DOUBLE'), jpype.JDouble) def testDouble(self): self._testFloat('DOUBLE', ('NAME', 'DOUBLE'), jpype.JDouble) def testReal(self): self._testFloat('REAL', ('NAME', 'REAL'), jpype.JFloat) def _testNumeric(self, tp, desc, jtype): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(NAME %s(5,2))" % tp) cu.execute("insert into test(NAME) values(?)", [1.25]) f = cu.execute("select * from test").fetchone() self.assertEqual(f[0], 1.25) self.assertIsInstance(f[0], decimal.Decimal) self.assertEqual(cu.description[0][0:2], desc) f = cu.execute("select * from test").fetchone(converters=None) self.assertEqual(f[0], decimal.Decimal(1.25)) self.assertIsInstance(f[0], jtype) cu.execute("delete from test") cu.execute("insert into test(NAME) values(?)", [None]) f = cu.execute("select * from test").fetchone(converters=None) self.assertEqual(f[0], None) def testNumeric(self): self._testNumeric('NUMERIC', ('NAME', 'DECIMAL'), java.math.BigDecimal) def testDecimal(self): self._testNumeric('DECIMAL', ('NAME', 'DECIMAL'), java.math.BigDecimal) def _testBinary(self, tp, desc, jtype): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(NAME %s)" % tp) v = bytes([1, 2, 3]) cu.execute("insert into test(NAME) values(?)", [v]) f = cu.execute("select * from test").fetchone() self.assertEqual(f[0], v) self.assertIsInstance(f[0], bytes) self.assertEqual(cu.description[0][0:2], desc) f = cu.execute("select * from test").fetchone(converters=None) self.assertEqual(bytes(f[0]), v) self.assertIsInstance(f[0], jtype) cu.execute("delete from test") cu.execute("insert into test(NAME) values(?)", [None]) f = cu.execute("select * from test").fetchone(converters=None) self.assertEqual(f[0], None) def testBinary(self): self._testBinary('BINARY(3)', ('NAME', 'VARBINARY'), JArray(JByte)) def testBlob(self): self._testBinary('BLOB', ('NAME', 'BLOB'), JArray(JByte)) def testLongVarBinary(self): self._testBinary('LONGVARBINARY', ('NAME', 'VARBINARY'), JArray(JByte)) def testVarBinary(self): self._testBinary('VARBINARY(10)', ('NAME', 'VARBINARY'), JArray(JByte)) def _testChars(self, tp, desc, jtype, v="hello"): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(NAME %s)" % tp) cu.execute("insert into test(NAME) values(?)", [v]) f = cu.execute("select * from test").fetchone() self.assertEqual(f[0], v) self.assertIsInstance(f[0], str) self.assertEqual(cu.description[0][0:2], desc) f = cu.execute("select * from test").fetchone(converters=None) self.assertEqual(f[0], v) self.assertIsInstance(f[0], jtype) cu.execute("delete from test") cu.execute("insert into test(NAME) values(?)", [None]) f = cu.execute("select * from test").fetchone(converters=None) self.assertEqual(f[0], None) def testChar(self): self._testChars('CHAR', ('NAME', 'CHAR'), java.lang.String, 'a') def testVarChar(self): self._testChars('VARCHAR', ('NAME', 'VARCHAR'), java.lang.String) def testLongVarChar(self): self._testChars('LONGVARCHAR', ('NAME', 'VARCHAR'), java.lang.String) def testClob(self): self._testChars('CLOB', ('NAME', 'CLOB'), java.lang.String) def testBoolean(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(NAME BOOLEAN)") cu.execute("insert into test(NAME) values(?)", [True]) f = cu.execute("select * from test").fetchone() self.assertEqual(f[0], True) self.assertIsInstance(f[0], int) self.assertEqual(cu.description[0][0:2], ('NAME', 'BOOLEAN')) f = cu.execute("select * from test").fetchone(converters=None) self.assertEqual(f[0], True) self.assertIsInstance(f[0], type(True)) cu.execute("delete from test") cu.execute("insert into test(NAME) values(?)", [None]) f = cu.execute("select * from test").fetchone(converters=None) self.assertEqual(f[0], None) class OtherTestCase(common.JPypeTestCase): """ This test is db dependent, but needed to check all code paths. """ def setUp(self): common.JPypeTestCase.setUp(self) if common.fast: raise common.unittest.SkipTest("fast") def tearDown(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: try: cur.execute("drop table test") except dbapi2.Error: pass def testJSON(self): got = [] class MyType(dbapi2.JDBCType): def get(self, rs, column, st): got.append(column) return dbapi2.JDBCType.get(self, rs, column, st) # Register a new type JSON = MyType("JSON", None) with dbapi2.connect(db_name, getters=dbapi2.GETTERS_BY_TYPE) as cx, cx.cursor() as cu: cu.execute("create table test(name JSON)") cu.execute("insert into test(name) values('{age: 31}')") f = cu.execute("select * from test").fetchone() self.assertEqual(got, [1]) with dbapi2.connect(db_name, getters=dbapi2.GETTERS_BY_NAME) as cx, cx.cursor() as cu: cu.execute("create table test(name JSON)") cu.execute("insert into test(name) values('{age: 31}')") f = cu.execute("select * from test").fetchone() self.assertEqual(got, [1, 1]) del dbapi2._registry[JSON] class ThreadingTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) if common.fast: raise common.unittest.SkipTest("fast") def tearDown(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: try: cur.execute("drop table test") except dbapi2.Error: pass def _testThread(self, cu, cmd, args, exc): error = [] def run(): try: cmd(*args) except Exception as ex: error.append(ex) t = threading.Thread(target=run) t.start() t.join() self.assertEqual(len(error), 1) with self.assertRaises(exc): raise error[0] def test_execute(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name VARCHAR(10))") self._testThread(cu, cu.execute, ("insert into test(name) values ('a')",), dbapi2.ProgrammingError) def test_executemany(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name VARCHAR(10))") self._testThread(cu, cu.executemany, ("insert into test(name) values ('?')", [[1]]), dbapi2.ProgrammingError) def test_fetchone(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name VARCHAR(10))") cu.execute("insert into test(name) values('a')") self._testThread(cu, cu.fetchone, (), dbapi2.ProgrammingError) def test_fetchmany(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name VARCHAR(10))") cu.execute("insert into test(name) values('a')") self._testThread(cu, cu.fetchmany, (), dbapi2.ProgrammingError) def test_fetchall(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name VARCHAR(10))") cu.execute("insert into test(name) values('a')") self._testThread(cu, cu.fetchall, (), dbapi2.ProgrammingError) def test_close(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name VARCHAR(10))") cu.execute("insert into test(name) values('a')") self._testThread(cu, cu.close, (), dbapi2.ProgrammingError) def test_callproc(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name VARCHAR(10))") cu.execute("insert into test(name) values('a')") self._testThread(cu, cu.callproc, ("lower", ["FOO"]), dbapi2.ProgrammingError) jpype-1.3.0/test/jpypetest/test_sql_hsqldb.py000066400000000000000000001504701405671516700214400ustar00rootroot00000000000000# This file is Public Domain and may be used without restrictions, # because noone should have to waste their lives typing this again. import _jpype import jpype from jpype.types import * from jpype import java import jpype.dbapi2 as dbapi2 import common import time import datetime import decimal import threading java = jpype.java try: import zlib except ImportError: zlib = None db_name = "jdbc:hsqldb:mem:myDb" #db_name = "jdbc:derby:memory:myDb" #first = "jdbc:derby:memory:myDb;create=True" class ConnectTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) if common.fast: raise common.unittest.SkipTest("fast") def testConnect(self): cx = dbapi2.connect(db_name) self.assertIsInstance(cx, dbapi2.Connection) def testClose(self): cx = dbapi2.connect(db_name) cx.close() # Closing twice is an error with self.assertRaises(dbapi2.ProgrammingError): cx.close() def testScope(self): with dbapi2.connect(db_name) as cx: pass with self.assertRaises(dbapi2.ProgrammingError): cx.close() def testAdapters(self): cx = dbapi2.connect(db_name) self.assertEqual(cx.adapters, dbapi2._default_adapters) cx = dbapi2.connect(db_name, adapters=None) self.assertEqual(cx.adapters, {}) m = {} cx = dbapi2.connect(db_name, adapters=m) self.assertEqual(cx.adapters, m) def testConverters(self): cx = dbapi2.connect(db_name) self.assertEqual(cx.converters, dbapi2._default_converters) cx = dbapi2.connect(db_name, converters=None) self.assertEqual(cx.converters, {}) m = {} cx = dbapi2.connect(db_name, converters=m) self.assertEqual(cx.converters, m) class ConnectionTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) if common.fast: raise common.unittest.SkipTest("fast") def test_commit(self): with dbapi2.connect(db_name) as cx: # Commit must work without a command cx.commit() def test_rollback(self): with dbapi2.connect(db_name) as cx: # Commit must work without a command cx.rollback() def test_cursor(self): with dbapi2.connect(db_name) as cx: self.assertIsInstance(cx.cursor(), dbapi2.Cursor) def testAdapters(self): with dbapi2.connect(db_name) as cx: m = {'foo': 1} cx.adapters = m self.assertEqual(cx._adapters, m) with self.assertRaises(TypeError): cx.adapters = object() def testConverters(self): with dbapi2.connect(db_name) as cx: m = {'foo': 1} cx.converters = m self.assertEqual(cx._converters, m) with self.assertRaises(TypeError): cx.converters = object() def testClosedClass(self): with dbapi2.connect(db_name) as cx: with self.assertRaises(AttributeError): cx.seters = object() def testAutocommitFail(self): with dbapi2.connect(db_name) as cx: cx.autocommit = True with self.assertRaises(dbapi2.NotSupportedError): cx.commit() with self.assertRaises(dbapi2.NotSupportedError): cx.rollback() def test_typeinfo(self): with dbapi2.connect(db_name) as cx: ti = cx.typeinfo self.assertIsInstance(ti, dict) for p, v in ti.items(): self.assertIsInstance(p, str) self.assertIsInstance(v, dbapi2.JDBCType) with self.assertRaises(dbapi2.ProgrammingError): ti = cx.typeinfo def test_connection(self): with dbapi2.connect(db_name) as cx: c = cx.connection self.assertIsInstance(c, java.sql.Connection) def test_getters(self): with dbapi2.connect(db_name) as cx: cx.getters = dbapi2.GETTERS_BY_NAME self.assertEqual(cx._getters, dbapi2.GETTERS_BY_NAME) self.assertEqual(cx.getters, dbapi2.GETTERS_BY_NAME) cx.getters = dbapi2.GETTERS_BY_TYPE self.assertEqual(cx._getters, dbapi2.GETTERS_BY_TYPE) self.assertEqual(cx.getters, dbapi2.GETTERS_BY_TYPE) def test_setters(self): with dbapi2.connect(db_name) as cx: cx.setters = dbapi2.SETTERS_BY_META self.assertEqual(cx._setters, dbapi2.SETTERS_BY_META) self.assertEqual(cx.setters, dbapi2.SETTERS_BY_META) cx.setters = dbapi2.SETTERS_BY_TYPE self.assertEqual(cx._setters, dbapi2.SETTERS_BY_TYPE) self.assertEqual(cx.setters, dbapi2.SETTERS_BY_TYPE) def test_adapters(self): with dbapi2.connect(db_name) as cx: self.assertEqual(cx.adapters, dbapi2._default_adapters) cx.adapters = None self.assertEqual(cx.adapters, {}) m = {} cx.adapters = m self.assertEqual(cx.adapters, m) with self.assertRaises(dbapi2.InterfaceError): cx.adapters = object() def test_converters(self): with dbapi2.connect(db_name) as cx: self.assertEqual(cx.converters, dbapi2._default_converters) cx.converters = None self.assertEqual(cx.converters, {}) m = {} cx.converters = m self.assertEqual(cx.converters, m) with self.assertRaises(dbapi2.InterfaceError): cx.converters = object() class CursorTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) if common.fast: raise common.unittest.SkipTest("fast") def tearDown(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: try: cur.execute("drop table booze") except dbapi2.Error: pass try: cur.execute("drop table barflys") except dbapi2.Error: pass def testCursorIsolation(self): with dbapi2.connect(db_name) as cx: # Make sure cursors created from the same connection have # the documented transaction isolation level cur1 = cx.cursor() cur2 = cx.cursor() cur1.execute("create table booze (name varchar(20))") cur1.execute("insert into booze values ('Victoria Bitter')") cur2.execute("select name from booze") booze = cur2.fetchall() self.assertEqual(len(booze), 1) self.assertEqual(len(booze[0]), 1) self.assertEqual(booze[0][0], "Victoria Bitter") def testDescription(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: cur.execute("create table booze (name varchar(20))") self.assertEqual( cur.description, None, "cursor.description should be none after executing a " "statement that can return no rows (such as create table)", ) cur.execute("select name from booze") self.assertEqual( len(cur.description), 1, "cursor.description describes too many columns" ) self.assertEqual( len(cur.description[0]), 7, "cursor.description[x] tuples must have 7 elements", ) self.assertEqual( cur.description[0][0].lower(), "name", "cursor.description[x][0] must return column name", ) self.assertEqual( cur.description[0][1], dbapi2.STRING, "cursor.description[x][1] must return column type. Got %r" % cur.description[0][1], ) # Make sure self.description gets reset cur.execute("create table barflys (name varchar(20))") self.assertEqual( cur.description, None, "cursor.description not being set to None when executing " "no-result statements (eg. create table)", ) def testRowcount(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: cur.execute("create table booze (name varchar(20))") # This was dropped from the specification # self.assertEqual( # cur.rowcount, # -1, # "cursor.rowcount should be -1 after executing no-result " "statements", # ) cur.execute("insert into booze values ('Victoria Bitter')") self.assertEqual( cur.rowcount, 1, "cursor.rowcount should == number or rows inserted, or " "set to -1 after executing an insert statement", ) cur.execute("select name from booze") self.assertEqual( cur.rowcount, -1, "cursor.rowcount should == number of rows returned, or " "set to -1 after executing a select statement", ) cur.execute("create table barflys (name varchar(20))") # THis test does not match jdbc parameters # self.assertEqual( # cur.rowcount, # -1, # "cursor.rowcount not being reset to -1 after executing " # "no-result statements", # ) def testClose(self): cx = dbapi2.connect(db_name) try: cur = cx.cursor() finally: cx.close() # cursor.execute should raise an Error if called after connection # closed with self.assertRaises(dbapi2.Error): cur.execute("create table booze (name varchar(20))") # connection.commit should raise an Error if called after connection' # closed.' self.assertRaises(dbapi2.Error, cx.commit) # connection.close should raise an Error if called more than once self.assertRaises(dbapi2.Error, cx.close) def test_None(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: cur.execute("create table booze (name varchar(20))") cur.execute("insert into booze values (NULL)") cur.execute("select name from booze") r = cur.fetchall() self.assertEqual(len(r), 1) self.assertEqual(len(r[0]), 1) self.assertEqual(r[0][0], None, "NULL value not returned as None") def testArraysize(self): # Not much here - rest of the tests for this are in test_fetchmany with dbapi2.connect(db_name) as cx, cx.cursor() as cur: self.assertTrue( hasattr(cur, "arraysize"), "cursor.arraysize must be defined" ) def _paraminsert(self, cur): cur.execute("create table booze (name varchar(20))") cur.execute("insert into booze values ('Victoria Bitter')") self.assertTrue(cur.rowcount in (-1, 1)) cur.execute("insert into booze values (?)", ("Cooper's",)) self.assertTrue(cur.rowcount in (-1, 1)) cur.execute("select name from booze") res = cur.fetchall() self.assertEqual(len(res), 2, "cursor.fetchall returned too few rows") beers = [res[0][0], res[1][0]] beers.sort() self.assertEqual( beers[0], "Cooper's", "cursor.fetchall retrieved incorrect data, or data inserted " "incorrectly", ) self.assertEqual( beers[1], "Victoria Bitter", "cursor.fetchall retrieved incorrect data, or data inserted " "incorrectly", ) def test_execute(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: self._paraminsert(cur) def test_executeBad(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: with self.assertRaises(dbapi2.InterfaceError): cur.execute("insert into booze values (?)", object()) with self.assertRaises(dbapi2.InterfaceError): cur.execute(object()) with self.assertRaises(dbapi2.ProgrammingError): cur.execute("inert into booze values (?)", [["?"]]) def test_setinputsizes(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: cur.setinputsizes((25,)) self._paraminsert(cur) # Make sure cursor still works def test_setoutputsize_basic(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: cur.setoutputsize(1000) cur.setoutputsize(2000, 0) self._paraminsert(cur) # Make sure the cursor still works def test_executemany(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: cur.execute("create table booze (name varchar(20))") largs = [("Cooper's",), ("Boag's",)] margs = [{"beer": "Cooper's"}, {"beer": "Boag's"}] cur.executemany("insert into booze values (?)", largs) self.assertEqual( cur.rowcount, 2, "insert using cursor.executemany set cursor.rowcount to " "incorrect value %r" % cur.rowcount, ) cur.execute("select name from booze") res = cur.fetchall() self.assertEqual( len(res), 2, "cursor.fetchall retrieved incorrect number of rows" ) beers = [res[0][0], res[1][0]] beers.sort() self.assertEqual(beers[0], "Boag's", "incorrect data retrieved") self.assertEqual(beers[1], "Cooper's", "incorrect data retrieved") def test_executemanyGenerator(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: def mygen(ls): for i in ls: yield [i] cu.execute("create table booze (name varchar(20))") cu.executemany("insert into booze values (?)", mygen(self.samples)) cu.execute("select * from booze") f = cu.fetchall() for i, v in enumerate(self.samples): self.assertEqual(f[i][0], v) def test_executemanyIterator(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: class myiter: def __init__(self, ls): self.ls = ls self.i = 0 def __iter__(self): return self def __next__(self): if self.i == len(self.ls): raise StopIteration rc = [self.ls[self.i]] self.i += 1 return rc cu.execute("create table booze (name varchar(20))") cu.executemany("insert into booze values (?)", myiter(self.samples)) cu.execute("select * from booze") f = cu.fetchall() for i, v in enumerate(self.samples): self.assertEqual(f[i][0], v) def test_executemanyBad(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table booze (name varchar(20))") with self.assertRaises(TypeError): cu.executemany("insert into booze values (?)", object()) with self.assertRaises(dbapi2.InterfaceError): cu.executemany("insert into booze values (?)", object()) with self.assertRaises(dbapi2.InterfaceError): cu.executemany(object(), []) with self.assertRaises(dbapi2.ProgrammingError): cu.executemany("insert into booze values (?)", None) with self.assertRaises(dbapi2.ProgrammingError): cu.executemany("inert into booze values (?)", [['?']]) def test_fetchone(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: # cursor.fetchone should raise an Error if called before # executing a select-type query self.assertRaises(dbapi2.ProgrammingError, cur.fetchone) # cursor.fetchone should raise an Error if called after # executing a query that cannot return rows cur.execute("create table booze (name varchar(20))") self.assertRaises(dbapi2.Error, cur.fetchone) cur.execute("select name from booze") self.assertEqual( cur.fetchone(), None, "cursor.fetchone should return None if a query retrieves " "no rows", ) self.assertEqual(cur.rowcount, -1) # cursor.fetchone should raise an Error if called after # executing a query that cannot return rows cur.execute("insert into booze values ('Victoria Bitter')") self.assertRaises(dbapi2.Error, cur.fetchone) cur.execute("select name from booze") r = cur.fetchone() self.assertEqual( len(r), 1, "cursor.fetchone should have retrieved a single row" ) self.assertEqual( r[0], "Victoria Bitter", "cursor.fetchone retrieved incorrect data" ) self.assertEqual( cur.fetchone(), None, "cursor.fetchone should return None if no more rows available", ) self.assertEqual(cur.rowcount, -1) samples = [ "Carlton Cold", "Carlton Draft", "Mountain Goat", "Redback", "Victoria Bitter", "XXXX", ] def _populate(self): """ Return a list of sql commands to setup the DB for the fetch tests. """ populate = [ "insert into booze values ('{}')".format(s) for s in self.samples ] return populate def test_fetchmany(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: # cursor.fetchmany should raise an Error if called without # issuing a query self.assertRaises(dbapi2.ProgrammingError, cur.fetchmany, 4) cur.execute("create table booze (name varchar(20))") for sql in self._populate(): cur.execute(sql) cur.execute("select name from booze") r = cur.fetchmany() self.assertEqual( len(r), 1, "cursor.fetchmany retrieved incorrect number of rows, " "default of arraysize is one.", ) cur.arraysize = 10 r = cur.fetchmany(3) # Should get 3 rows self.assertEqual( len(r), 3, "cursor.fetchmany retrieved incorrect number of rows" ) r = cur.fetchmany(4) # Should get 2 more self.assertEqual( len(r), 2, "cursor.fetchmany retrieved incorrect number of rows" ) r = cur.fetchmany(4) # Should be an empty sequence self.assertEqual( len(r), 0, "cursor.fetchmany should return an empty sequence after " "results are exhausted", ) self.assertEqual(cur.rowcount, -1) # Same as above, using cursor.arraysize cur.arraysize = 4 cur.execute("select name from booze") r = cur.fetchmany() # Should get 4 rows self.assertEqual( len(r), 4, "cursor.arraysize not being honoured by fetchmany" ) r = cur.fetchmany() # Should get 2 more self.assertEqual(len(r), 2) r = cur.fetchmany() # Should be an empty sequence self.assertEqual(len(r), 0) self.assertEqual(cur.rowcount, -1) cur.arraysize = 6 cur.execute("select name from booze") rows = cur.fetchmany() # Should get all rows self.assertTrue(cur.rowcount in (-1, 6)) self.assertEqual(len(rows), 6) self.assertEqual(len(rows), 6) rows = [r[0] for r in rows] rows.sort() # Make sure we get the right data back out for i in range(0, 6): self.assertEqual( rows[i], self.samples[i], "incorrect data retrieved by cursor.fetchmany", ) rows = cur.fetchmany() # Should return an empty list self.assertEqual( len(rows), 0, "cursor.fetchmany should return an empty sequence if " "called after the whole result set has been fetched", ) self.assertEqual(cur.rowcount, -1) cur.execute("create table barflys (name varchar(20))") cur.execute("select name from barflys") r = cur.fetchmany() # Should get empty sequence self.assertEqual( len(r), 0, "cursor.fetchmany should return an empty sequence if " "query retrieved no rows", ) def test_fetchall(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: # cursor.fetchall should raise an Error if called # without executing a query that may return rows (such # as a select) self.assertRaises(dbapi2.Error, cur.fetchall) cur.execute("create table booze (name varchar(20))") for sql in self._populate(): cur.execute(sql) # cursor.fetchall should raise an Error if called # after executing a statement that cannot return rows self.assertRaises(dbapi2.ProgrammingError, cur.fetchall) cur.execute("select name from booze") rows = cur.fetchall() self.assertEqual(cur.rowcount, -1) self.assertEqual( len(rows), len(self.samples), "cursor.fetchall did not retrieve all rows", ) rows = [r[0] for r in rows] rows.sort() for i in range(0, len(self.samples)): self.assertEqual( rows[i], self.samples[i], "cursor.fetchall retrieved incorrect rows" ) rows = cur.fetchall() self.assertEqual( len(rows), 0, "cursor.fetchall should return an empty list if called " "after the whole result set has been fetched", ) self.assertEqual(cur.rowcount, -1) cur.execute("create table barflys (name varchar(20))") cur.execute("select name from barflys") rows = cur.fetchall() self.assertEqual(cur.rowcount, -1) self.assertEqual( len(rows), 0, "cursor.fetchall should return an empty list if " "a select query returns no rows", ) def test_mixedfetch(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: cur.execute("create table booze (name varchar(20))") for sql in self._populate(): cur.execute(sql) cur.execute("select name from booze") self.assertEqual(cur.rowcount, -1) rows1 = cur.fetchone() rows23 = cur.fetchmany(2) rows4 = cur.fetchone() rows56 = cur.fetchall() self.assertEqual(cur.rowcount, -1) self.assertEqual( len(rows23), 2, "fetchmany returned incorrect number of rows" ) self.assertEqual( len(rows56), 2, "fetchall returned incorrect number of rows" ) rows = [rows1[0]] rows.extend([rows23[0][0], rows23[1][0]]) rows.append(rows4[0]) rows.extend([rows56[0][0], rows56[1][0]]) rows.sort() for i in range(0, len(self.samples)): self.assertEqual( rows[i], self.samples[i], "incorrect data retrieved or inserted" ) def test_nextset(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table booze (name varchar(20))") booze = ["Wiskey", ] cu.execute("insert into booze(name) values (?)", booze) self.assertEqual(cu.rowcount, 1) with self.assertRaises(dbapi2.ProgrammingError): cu.execute("select * from booze; select * from booze") def test_lastrowid(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table booze(id INTEGER IDENTITY PRIMARY KEY, name varchar(255))") cu.execute("insert into booze(name) values('hello')", keys=True) id0 = cu.lastrowid self.assertIsInstance(id0, int) # Call more than once id1 = cu.lastrowid self.assertIsInstance(id1, int) cx.commit() cu.execute("insert into booze(name) values('there')", keys=True) id2 = cu.lastrowid self.assertIsInstance(id2, int) cu.execute("select * from booze") f = cu.fetchall() self.assertEqual(cu.lastrowid, None) self.assertEqual(f[0][0], id0) self.assertEqual(f[1][0], id2) def test_lastrowidMany(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table booze(id INTEGER IDENTITY PRIMARY KEY, name varchar(255))") cu.executemany("insert into booze(name) values(?)", [['Redback'], ['Fat Yak']], keys=True) ids = cu.lastrowid self.assertIsInstance(ids, list) self.assertEqual(len(ids), 2) cu.execute("select * from booze") f = cu.fetchall() self.assertEqual(f[0][0], ids[0]) self.assertEqual(f[1][0], ids[1]) def test_iter(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: ls = [['Tooheys Old'], ['Nine Tales Original Amber Ale'], ['Dogbolter']] cu.execute("create table booze(name varchar(255))") cu.executemany("insert into booze(name) values(?)", ls, keys=True) # make sure we throw if there is no result set with self.assertRaises(dbapi2.ProgrammingError): for booze in cu: pass cu.execute("select * from booze") for i, booze in enumerate(cu): self.assertEqual(ls[i], booze) def testNoAdapter(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table booze(name varchar(50))") with self.assertRaises(dbapi2.InterfaceError): cu.execute("insert into booze(name) values(?)", [object()]) def testBadParameters(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table booze(name varchar(50))") with self.assertRaises(dbapi2.InterfaceError): cu.execute("insert into booze(name) values(?)", object()) def test_callproc(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: r = cu.callproc("lower", ("FOO",)) self.assertEqual(len(r), 1) self.assertEqual(r[0], "FOO") r = cu.fetchall() self.assertEqual(len(r), 1) self.assertEqual(len(r[0]), 1) self.assertEqual(r[0][0], "foo") def test_callprocBad(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: with self.assertRaises(dbapi2.ProgrammingError): r = cu.callproc("not_there", ("FOO",)) with self.assertRaises(dbapi2.InterfaceError): r = cu.callproc(object(), ("FOO",)) with self.assertRaises(dbapi2.InterfaceError): r = cu.callproc("lower", (object(),)) with self.assertRaises(dbapi2.InterfaceError): r = cu.callproc("lower", object()) def test_close(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.close() with self.assertRaises(dbapi2.ProgrammingError): cu.close() def test_parameters(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: with self.assertRaises(dbapi2.ProgrammingError): p = cu.parameters cu.execute("create table booze(name varchar(50))") cu.execute("insert into booze(name) values(?)", ('Hahn Super Dry',)) p = cu.parameters self.assertEqual(p[0][0:2], ('VARCHAR', dbapi2.VARCHAR)) def test_resultSet(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table booze(name varchar(50))") cu.execute("insert into booze(name) values(?)", ('Hahn Super Dry',)) cu.execute("select * from booze") rs = cu.resultSet self.assertIsInstance(rs, java.sql.ResultSet) def test_fetchClosed(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table booze(name varchar(50))") cu.execute("insert into booze(name) values(?)", ('Hahn Super Dry',)) cu.execute("select * from booze") cu.close() with self.assertRaises(dbapi2.ProgrammingError): cu.fetchone() with self.assertRaises(dbapi2.ProgrammingError): cu.fetchmany() with self.assertRaises(dbapi2.ProgrammingError): cu.fetchall() self.assertEqual(cu.resultSet, None) def test_executeBadParameters(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: def mygen(ls): for i in ls: yield i cu.execute("create table booze(name varchar(50), price integer)") with self.assertRaises(dbapi2.ProgrammingError): cu.executemany("insert into booze(name,price) values(?,?)", [('Hahn Super Dry', 2), ('Coors',)]) with self.assertRaises(dbapi2.InterfaceError): cu.execute("insert into booze(name,price) values(?,?)", {'name': 'Budweiser', 'price': 10}) with self.assertRaises(dbapi2.ProgrammingError): cu.executemany("insert into booze(name,price) values(?,?)", mygen([['Budweiser']])) cu.execute("insert into booze(name,price) values(?,?)", mygen(['Pabst Blue Robot', 20000])) with self.assertRaises(dbapi2.ProgrammingError): cu.execute("insert into booze(name,price) values(?,?)", mygen(['Budweiser'])) with self.assertRaises(dbapi2.InterfaceError): cu.execute("insert into booze(name,price) values(?,?)", 'Budweiser') with self.assertRaises(dbapi2.ProgrammingError): cu.execute("insert into booze(name,price) values(?,?)", mygen(['Budweiser', 2, 'no'])) with self.assertRaises(dbapi2.InterfaceError): cu.execute("insert into booze(name,price) values(?,?)", object()) class AdapterTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) if common.fast: raise common.unittest.SkipTest("fast") self.testdata = b"abcdefg" * 10 self.params = memoryview(zlib.compress(self.testdata)) def tearDown(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: try: cur.execute("drop table test") except dbapi2.Error: pass def testOnConnector(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name varchar(255))") cx.adapters[object] = lambda x: "none" cu.execute("insert into test(name) values(?)", [object()]) cu.execute("select * from test") f = cu.fetchall() self.assertEqual(f[0][0], "none") @common.unittest.skipUnless(zlib, "requires zlib") class ConverterTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) if common.fast: raise common.unittest.SkipTest("fast") self.testdata = b"abcdefg" * 10 self.params = memoryview(zlib.compress(self.testdata)) def tearDown(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: try: cur.execute("drop table test") except dbapi2.Error: pass @staticmethod def convert(s): return zlib.decompress(s) def testConvertersBad(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name varchar(20))") cu.executemany("insert into test(name) values(?)", [['alice'], ['bob'], ['charlie']]) cu.execute("select name from test") with self.assertRaises(dbapi2.ProgrammingError): cu.fetchone(converters=[]) cu.execute("select name from test") with self.assertRaises(dbapi2.InterfaceError): cu.fetchone(converters=[int]) cu.execute("select name from test") with self.assertRaises(dbapi2.ProgrammingError): cu.fetchone(converters=[str, str]) def testConvertersNone(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name varchar(20))") cu.executemany("insert into test(name) values(?)", [['alice'], ['bob'], ['charlie']]) cu.execute("select name from test") f = cu.fetchone(converters=None) self.assertIsInstance(f[0], java.lang.String) cu.execute("select name from test") def testConvertersPositional(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name varchar(20))") cu.executemany("insert into test(name) values(?)", [['alice'], ['bob'], ['charlie']]) cu.execute("select name from test") f = cu.fetchone(converters=[str]) self.assertIsInstance(f[0], str) cu.execute("select name from test") def test_fetchoneTypesPositional(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name varchar(20))") cu.executemany("insert into test(name) values(?)", [['alice'], ['bob'], ['charlie']]) cu.execute("select name from test") f = cu.fetchone(types=[dbapi2.STRING]) self.assertIsInstance(f[0], str) def test_fetchmanyTypesPositional(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name varchar(20))") cu.executemany("insert into test(name) values(?)", [['alice'], ['bob'], ['charlie']]) cu.execute("select name from test") f = cu.fetchmany(types=[dbapi2.STRING]) self.assertIsInstance(f[0][0], str) def test_fetchallTypesPositional(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name varchar(20))") cu.executemany("insert into test(name) values(?)", [['alice'], ['bob'], ['charlie']]) cu.execute("select name from test") f = cu.fetchall(types=[dbapi2.STRING]) self.assertIsInstance(f[0][0], str) def testTypesPositionalBAD(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name varchar(20))") cu.executemany("insert into test(name) values(?)", [['alice'], ['bob'], ['charlie']]) cu.execute("select name from test") with self.assertRaises(dbapi2.ProgrammingError): f = cu.fetchone(types=[dbapi2.STRING, dbapi2.STRING]) with self.assertRaises(dbapi2.ProgrammingError): f = cu.fetchone(types=[]) class GettersTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) if common.fast: raise common.unittest.SkipTest("fast") self.testdata = b"abcdefg" * 10 self.params = memoryview(zlib.compress(self.testdata)) def tearDown(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: try: cur.execute("drop table test") except dbapi2.Error: pass @common.unittest.skip class TransactionsTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) if common.fast: raise common.unittest.SkipTest("fast") def tearDown(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: try: cur.execute("drop table test") except dbapi2.Error: pass def testTransactionRollbackCreate(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cx.commit() # needed before starting transactions cu.execute("begin") cu.execute("create table test(name VARCHAR(10))") cx.rollback() # with self.assertRaises(dbapi2.ProgrammingError): cu.execute("select * from test") def testTransactionRollbackInsert(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cx.commit() # needed before starting transactions cu.execute("create table test(name VARCHAR(10))") cx.commit() cu.execute("begin") cu.execute("insert into test(name) values('alice')") cx.rollback() # Alice should go away result = cu.execute("select * from test").fetchall() self.assertEqual(result, []) def testTransactionRollbackClose(self): with dbapi2.connect(db_name) as cx2: with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cx.commit() # needed before starting transactions cu.execute("create table test(name VARCHAR(10))") cu.execute("insert into test(name) values('alice')") cx.commit() cu.execute("begin") cu.execute("insert into test(name) values('bob')") result = cu.execute("select * from test").fetchall() self.assertEqual(result, [['alice'], ['bob']]) # Bob should go away with cx2.cursor() as cu: result = cu.execute("select * from test").fetchall() self.assertEqual(result, [['alice']]) class TypeTestCase(common.JPypeTestCase): """ This test is db dependent, but needed to check all code paths. """ def setUp(self): common.JPypeTestCase.setUp(self) if common.fast: raise common.unittest.SkipTest("fast") def tearDown(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: try: cur.execute("drop table test") except dbapi2.Error: pass def testTime(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(NAME TIME)") cu.execute("select * from test") cu.execute("insert into test(NAME) values('12:05:10')") f = cu.execute('select * from test').fetchone() self.assertIsInstance(f[0], datetime.time) cu.execute("delete from test") cu.execute("insert into test(NAME) values(?)", f) f2 = cu.execute('select * from test').fetchone() self.assertEqual(f2, f) cu.execute("delete from test") # Test with Java t1 = jpype.java.sql.Time(1, 2, 3) cu.execute("insert into test(NAME) values(?)", [t1]) f3 = cu.execute('select * from test').fetchone() self.assertEqual(f3[0], datetime.time(1, 2, 3)) f4 = cu.execute('select * from test').fetchone(converters=None) self.assertEqual(f4[0], t1) self.assertIsInstance(f4[0], jpype.java.sql.Time) cu.execute("delete from test") # Test with dbapi2.Time t1 = dbapi2.Time(6, 21, 32) cu.execute("insert into test(NAME) values(?)", [t1]) f3 = cu.execute('select * from test').fetchone() self.assertEqual(f3[0], datetime.time(6, 21, 32)) def testDate(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(NAME DATE)") cu.execute("select * from test") cu.execute("insert into test(NAME) values('2012-02-05')") f = cu.execute('select * from test').fetchone() self.assertIsInstance(f[0], datetime.date) cu.execute("delete from test") cu.execute("insert into test(NAME) values(?)", f) f2 = cu.execute('select * from test').fetchone() self.assertEqual(f2, f) cu.execute("delete from test") # Test with Java t1 = java.sql.Date(1972 - 1900, 4 - 1, 1) cu.execute("insert into test(NAME) values(?)", [t1]) f3 = cu.execute('select * from test').fetchone() self.assertEqual(f3[0], datetime.date(1972, 4, 1)) f4 = cu.execute('select * from test').fetchone(converters=None) self.assertEqual(f4[0], t1) self.assertIsInstance(f4[0], java.sql.Date) cu.execute("delete from test") # Test with dbapi2.Date t1 = dbapi2.Date(2020, 5, 21) cu.execute("insert into test(NAME) values(?)", [t1]) f3 = cu.execute('select * from test').fetchone() self.assertEqual(f3[0], datetime.date(2020, 5, 21)) def testTimestamp(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(NAME TIMESTAMP)") cu.execute("select * from test") cu.execute("insert into test(NAME) values('2012-02-05 12:02:45.123')") f = cu.execute('select * from test').fetchone() self.assertIsInstance(f[0], datetime.date) cu.execute("delete from test") cu.execute("insert into test(NAME) values(?)", f) f2 = cu.execute('select * from test').fetchone() self.assertEqual(f2, f) cu.execute("delete from test") # Test with Java t1 = java.sql.Timestamp(1972 - 1900, 4 - 1, 1, 12, 2, 45, 123456000) cu.execute("insert into test(NAME) values(?)", [t1]) f3 = cu.execute('select * from test').fetchone() self.assertEqual(f3[0], datetime.datetime(1972, 4, 1, 12, 2, 45, 123456)) f4 = cu.execute('select * from test').fetchone(converters=None) self.assertEqual(f4[0], t1) self.assertIsInstance(f4[0], java.sql.Timestamp) cu.execute("delete from test") # Test with dbapi2.Date t1 = dbapi2.Timestamp(2020, 5, 21, 3, 4, 5, 123122000) cu.execute("insert into test(NAME) values(?)", [t1]) f3 = cu.execute('select * from test').fetchone() self.assertEqual(f3[0], datetime.datetime(2020, 5, 21, 3, 4, 5, 123122)) def _testInt(self, tp, desc, jtype, null=True): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(NAME %s)" % tp) cu.execute("insert into test(NAME) values(?)", [123]) f = cu.execute("select * from test").fetchone() self.assertEqual(f[0], 123) self.assertIsInstance(f[0], int) self.assertEqual(cu.description[0][0:2], desc) f = cu.execute("select * from test").fetchone(converters=None) self.assertEqual(f[0], 123) self.assertIsInstance(f[0], jtype) cu.execute("delete from test") if null: cu.execute("insert into test(NAME) values(?)", [None]) f = cu.execute("select * from test").fetchone(converters=None) self.assertEqual(f[0], None) def testTinyInt(self): self._testInt('TINYINT', ('NAME', 'TINYINT'), jpype.JShort) def testBigInt(self): self._testInt('BIGINT', ('NAME', 'BIGINT'), jpype.JLong) def testIdentity(self): self._testInt('IDENTITY', ('NAME', 'INTEGER'), jpype.JInt, False) def testInteger(self): self._testInt('INTEGER', ('NAME', 'INTEGER'), jpype.JInt) def testSmallInt(self): self._testInt('SMALLINT', ('NAME', 'SMALLINT'), jpype.JShort) def _testFloat(self, tp, desc, jtype): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(NAME %s)" % tp) cu.execute("insert into test(NAME) values(?)", [1.25]) f = cu.execute("select * from test").fetchone() self.assertEqual(f[0], 1.25) self.assertIsInstance(f[0], float) self.assertEqual(cu.description[0][0:2], desc) f = cu.execute("select * from test").fetchone(converters=None) self.assertEqual(f[0], 1.25) self.assertIsInstance(f[0], jtype) cu.execute("delete from test") cu.execute("insert into test(NAME) values(?)", [None]) f = cu.execute("select * from test").fetchone(converters=None) self.assertEqual(f[0], None) def testFloat(self): self._testFloat('FLOAT', ('NAME', 'DOUBLE'), jpype.JDouble) def testDouble(self): self._testFloat('DOUBLE', ('NAME', 'DOUBLE'), jpype.JDouble) def testReal(self): self._testFloat('REAL', ('NAME', 'DOUBLE'), jpype.JDouble) def _testNumeric(self, tp, desc, jtype): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(NAME %s(5,2))" % tp) cu.execute("insert into test(NAME) values(?)", [1.25]) f = cu.execute("select * from test").fetchone() self.assertEqual(f[0], 1.25) self.assertIsInstance(f[0], decimal.Decimal) self.assertEqual(cu.description[0][0:2], desc) f = cu.execute("select * from test").fetchone(converters=None) self.assertEqual(f[0], decimal.Decimal(1.25)) self.assertIsInstance(f[0], jtype) cu.execute("delete from test") cu.execute("insert into test(NAME) values(?)", [None]) f = cu.execute("select * from test").fetchone(converters=None) self.assertEqual(f[0], None) def testNumeric(self): self._testNumeric('NUMERIC', ('NAME', 'NUMERIC'), java.math.BigDecimal) def testDecimal(self): self._testNumeric('DECIMAL', ('NAME', 'DECIMAL'), java.math.BigDecimal) def _testBinary(self, tp, desc, jtype): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(NAME %s)" % tp) v = bytes([1, 2, 3]) cu.execute("insert into test(NAME) values(?)", [v]) f = cu.execute("select * from test").fetchone() self.assertEqual(f[0], v) self.assertIsInstance(f[0], bytes) self.assertEqual(cu.description[0][0:2], desc) f = cu.execute("select * from test").fetchone(converters=None) self.assertEqual(bytes(f[0]), v) self.assertIsInstance(f[0], jtype) cu.execute("delete from test") cu.execute("insert into test(NAME) values(?)", [None]) f = cu.execute("select * from test").fetchone(converters=None) self.assertEqual(f[0], None) def testBinary(self): self._testBinary('BINARY(3)', ('NAME', 'BINARY'), JArray(JByte)) def testBlob(self): self._testBinary('BLOB', ('NAME', 'BLOB'), JArray(JByte)) def testLongVarBinary(self): self._testBinary('LONGVARBINARY', ('NAME', 'VARBINARY'), JArray(JByte)) def testVarBinary(self): self._testBinary('VARBINARY(10)', ('NAME', 'VARBINARY'), JArray(JByte)) def _testChars(self, tp, desc, jtype, v="hello"): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(NAME %s)" % tp) cu.execute("insert into test(NAME) values(?)", [v]) f = cu.execute("select * from test").fetchone() self.assertEqual(f[0], v) self.assertIsInstance(f[0], str) self.assertEqual(cu.description[0][0:2], desc) f = cu.execute("select * from test").fetchone(converters=None) self.assertEqual(f[0], v) self.assertIsInstance(f[0], jtype) cu.execute("delete from test") cu.execute("insert into test(NAME) values(?)", [None]) f = cu.execute("select * from test").fetchone(converters=None) self.assertEqual(f[0], None) def testChar(self): self._testChars('CHAR', ('NAME', 'CHARACTER'), java.lang.String, 'a') def testVarChar(self): self._testChars('VARCHAR(10)', ('NAME', 'VARCHAR'), java.lang.String) def testLongVarChar(self): self._testChars('LONGVARCHAR', ('NAME', 'VARCHAR'), java.lang.String) def testClob(self): self._testChars('CLOB', ('NAME', 'CLOB'), java.lang.String) def testBoolean(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(NAME BOOLEAN)") cu.execute("insert into test(NAME) values(?)", [True]) f = cu.execute("select * from test").fetchone() self.assertEqual(f[0], True) self.assertIsInstance(f[0], int) self.assertEqual(cu.description[0][0:2], ('NAME', 'BOOLEAN')) f = cu.execute("select * from test").fetchone(converters=None) self.assertEqual(f[0], True) self.assertIsInstance(f[0], type(True)) cu.execute("delete from test") cu.execute("insert into test(NAME) values(?)", [None]) f = cu.execute("select * from test").fetchone(converters=None) self.assertEqual(f[0], None) class ThreadingTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) if common.fast: raise common.unittest.SkipTest("fast") def tearDown(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: try: cur.execute("drop table test") except dbapi2.Error: pass def _testThread(self, cu, cmd, args, exc): error = [] def run(): try: cmd(*args) except Exception as ex: error.append(ex) t = threading.Thread(target=run) t.start() t.join() self.assertEqual(len(error), 1) with self.assertRaises(exc): raise error[0] def test_execute(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name VARCHAR(10))") self._testThread(cu, cu.execute, ("insert into test(name) values ('a')",), dbapi2.ProgrammingError) def test_executemany(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name VARCHAR(10))") self._testThread(cu, cu.executemany, ("insert into test(name) values ('?')", [[1]]), dbapi2.ProgrammingError) def test_fetchone(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name VARCHAR(10))") cu.execute("insert into test(name) values('a')") self._testThread(cu, cu.fetchone, (), dbapi2.ProgrammingError) def test_fetchmany(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name VARCHAR(10))") cu.execute("insert into test(name) values('a')") self._testThread(cu, cu.fetchmany, (), dbapi2.ProgrammingError) def test_fetchall(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name VARCHAR(10))") cu.execute("insert into test(name) values('a')") self._testThread(cu, cu.fetchall, (), dbapi2.ProgrammingError) def test_close(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name VARCHAR(10))") cu.execute("insert into test(name) values('a')") self._testThread(cu, cu.close, (), dbapi2.ProgrammingError) def test_callproc(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name VARCHAR(10))") cu.execute("insert into test(name) values('a')") self._testThread(cu, cu.callproc, ("lower", ["FOO"]), dbapi2.ProgrammingError) jpype-1.3.0/test/jpypetest/test_sql_sqlite.py000066400000000000000000001535261405671516700214710ustar00rootroot00000000000000# This file is Public Domain and may be used without restrictions, # because noone should have to waste their lives typing this again. import _jpype import jpype from jpype.types import * from jpype import java import jpype.dbapi2 as dbapi2 import common import time import datetime import decimal import threading java = jpype.java try: import zlib except ImportError: zlib = None db_name = "jdbc:sqlite::memory:" class ConnectTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) if common.fast: raise common.unittest.SkipTest("fast") def testConnect(self): cx = dbapi2.connect(db_name) self.assertIsInstance(cx, dbapi2.Connection) def testClose(self): cx = dbapi2.connect(db_name) cx.close() # Closing twice is an error with self.assertRaises(dbapi2.ProgrammingError): cx.close() def testScope(self): with dbapi2.connect(db_name) as cx: pass with self.assertRaises(dbapi2.ProgrammingError): cx.close() def testAdapters(self): cx = dbapi2.connect(db_name) self.assertEqual(cx.adapters, dbapi2._default_adapters) cx = dbapi2.connect(db_name, adapters=None) self.assertEqual(cx.adapters, {}) m = {} cx = dbapi2.connect(db_name, adapters=m) self.assertEqual(cx.adapters, m) def testConverters(self): cx = dbapi2.connect(db_name) self.assertEqual(cx.converters, dbapi2._default_converters) cx = dbapi2.connect(db_name, converters=None) self.assertEqual(cx.converters, {}) m = {} cx = dbapi2.connect(db_name, converters=m) self.assertEqual(cx.converters, m) class ConnectionTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) if common.fast: raise common.unittest.SkipTest("fast") def test_commit(self): with dbapi2.connect(db_name) as cx: # Commit must work without a command cx.commit() def test_rollback(self): with dbapi2.connect(db_name) as cx: # Commit must work without a command cx.rollback() def test_cursor(self): with dbapi2.connect(db_name) as cx: self.assertIsInstance(cx.cursor(), dbapi2.Cursor) def testAdapters(self): with dbapi2.connect(db_name) as cx: m = {'foo': 1} cx.adapters = m self.assertEqual(cx._adapters, m) with self.assertRaises(TypeError): cx.adapters = object() def testConverters(self): with dbapi2.connect(db_name) as cx: m = {'foo': 1} cx.converters = m self.assertEqual(cx._converters, m) with self.assertRaises(TypeError): cx.converters = object() def testClosedClass(self): with dbapi2.connect(db_name) as cx: with self.assertRaises(AttributeError): cx.seters = object() def testAutocommitFail(self): with dbapi2.connect(db_name) as cx: cx.autocommit = True with self.assertRaises(dbapi2.NotSupportedError): cx.commit() with self.assertRaises(dbapi2.NotSupportedError): cx.rollback() def test_typeinfo(self): with dbapi2.connect(db_name) as cx: ti = cx.typeinfo self.assertIsInstance(ti, dict) for p, v in ti.items(): self.assertIsInstance(p, str) self.assertIsInstance(v, dbapi2.JDBCType) with self.assertRaises(dbapi2.ProgrammingError): ti = cx.typeinfo def test_connection(self): with dbapi2.connect(db_name) as cx: c = cx.connection self.assertIsInstance(c, java.sql.Connection) def test_getters(self): with dbapi2.connect(db_name) as cx: cx.getters = dbapi2.GETTERS_BY_NAME self.assertEqual(cx._getters, dbapi2.GETTERS_BY_NAME) self.assertEqual(cx.getters, dbapi2.GETTERS_BY_NAME) cx.getters = dbapi2.GETTERS_BY_TYPE self.assertEqual(cx._getters, dbapi2.GETTERS_BY_TYPE) self.assertEqual(cx.getters, dbapi2.GETTERS_BY_TYPE) def test_setters(self): with dbapi2.connect(db_name) as cx: cx.setters = dbapi2.SETTERS_BY_META self.assertEqual(cx._setters, dbapi2.SETTERS_BY_META) self.assertEqual(cx.setters, dbapi2.SETTERS_BY_META) cx.setters = dbapi2.SETTERS_BY_TYPE self.assertEqual(cx._setters, dbapi2.SETTERS_BY_TYPE) self.assertEqual(cx.setters, dbapi2.SETTERS_BY_TYPE) def test_adapters(self): with dbapi2.connect(db_name) as cx: self.assertEqual(cx.adapters, dbapi2._default_adapters) cx.adapters = None self.assertEqual(cx.adapters, {}) m = {} cx.adapters = m self.assertEqual(cx.adapters, m) with self.assertRaises(dbapi2.InterfaceError): cx.adapters = object() def test_converters(self): with dbapi2.connect(db_name) as cx: self.assertEqual(cx.converters, dbapi2._default_converters) cx.converters = None self.assertEqual(cx.converters, {}) m = {} cx.converters = m self.assertEqual(cx.converters, m) with self.assertRaises(dbapi2.InterfaceError): cx.converters = object() class CursorTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) if common.fast: raise common.unittest.SkipTest("fast") def tearDown(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: try: cur.execute("drop table booze") except dbapi2.Error: pass try: cur.execute("drop table barflys") except dbapi2.Error: pass def testCursorIsolation(self): with dbapi2.connect(db_name) as cx: # Make sure cursors created from the same connection have # the documented transaction isolation level cur1 = cx.cursor() cur2 = cx.cursor() cur1.execute("create table booze (name varchar(20))") cur1.execute("insert into booze values ('Victoria Bitter')") cur2.execute("select name from booze") booze = cur2.fetchall() self.assertEqual(len(booze), 1) self.assertEqual(len(booze[0]), 1) self.assertEqual(booze[0][0], "Victoria Bitter") def testDescription(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: cur.execute("create table booze (name varchar(20))") self.assertEqual( cur.description, None, "cursor.description should be none after executing a " "statement that can return no rows (such as create table)", ) cur.execute("select name from booze") self.assertEqual( len(cur.description), 1, "cursor.description describes too many columns" ) self.assertEqual( len(cur.description[0]), 7, "cursor.description[x] tuples must have 7 elements", ) self.assertEqual( cur.description[0][0].lower(), "name", "cursor.description[x][0] must return column name", ) self.assertEqual( cur.description[0][1], dbapi2.STRING, "cursor.description[x][1] must return column type. Got %r" % cur.description[0][1], ) # Make sure self.description gets reset cur.execute("create table barflys (name varchar(20))") self.assertEqual( cur.description, None, "cursor.description not being set to None when executing " "no-result statements (eg. create table)", ) def testRowcount(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: cur.execute("create table booze (name varchar(20))") # This was dropped from the specification # self.assertEqual( # cur.rowcount, # -1, # "cursor.rowcount should be -1 after executing no-result " "statements", # ) cur.execute("insert into booze values ('Victoria Bitter')") self.assertEqual( cur.rowcount, 1, "cursor.rowcount should == number or rows inserted, or " "set to -1 after executing an insert statement", ) cur.execute("select name from booze") self.assertEqual( cur.rowcount, -1, "cursor.rowcount should == number of rows returned, or " "set to -1 after executing a select statement", ) cur.execute("create table barflys (name varchar(20))") # THis test does not match jdbc parameters # self.assertEqual( # cur.rowcount, # -1, # "cursor.rowcount not being reset to -1 after executing " # "no-result statements", # ) def testClose(self): cx = dbapi2.connect(db_name) try: cur = cx.cursor() finally: cx.close() # cursor.execute should raise an Error if called after connection # closed with self.assertRaises(dbapi2.Error): cur.execute("create table booze (name varchar(20))") # connection.commit should raise an Error if called after connection' # closed.' self.assertRaises(dbapi2.Error, cx.commit) # connection.close should raise an Error if called more than once self.assertRaises(dbapi2.Error, cx.close) def test_None(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: cur.execute("create table booze (name varchar(20))") cur.execute("insert into booze values (NULL)") cur.execute("select name from booze") r = cur.fetchall() self.assertEqual(len(r), 1) self.assertEqual(len(r[0]), 1) self.assertEqual(r[0][0], None, "NULL value not returned as None") def testArraysize(self): # Not much here - rest of the tests for this are in test_fetchmany with dbapi2.connect(db_name) as cx, cx.cursor() as cur: self.assertTrue( hasattr(cur, "arraysize"), "cursor.arraysize must be defined" ) def _paraminsert(self, cur): cur.execute("create table booze (name varchar(20))") cur.execute("insert into booze values ('Victoria Bitter')") self.assertTrue(cur.rowcount in (-1, 1)) cur.execute("insert into booze values (?)", ("Cooper's",)) self.assertTrue(cur.rowcount in (-1, 1)) cur.execute("select name from booze") res = cur.fetchall() self.assertEqual(len(res), 2, "cursor.fetchall returned too few rows") beers = [res[0][0], res[1][0]] beers.sort() self.assertEqual( beers[0], "Cooper's", "cursor.fetchall retrieved incorrect data, or data inserted " "incorrectly", ) self.assertEqual( beers[1], "Victoria Bitter", "cursor.fetchall retrieved incorrect data, or data inserted " "incorrectly", ) def test_execute(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: self._paraminsert(cur) def test_executeBad(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: with self.assertRaises(dbapi2.InterfaceError): cur.execute("insert into booze values (?)", object()) with self.assertRaises(dbapi2.InterfaceError): cur.execute(object()) with self.assertRaises(dbapi2.ProgrammingError): cur.execute("inert into booze values (?)", [["?"]]) def test_setinputsizes(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: cur.setinputsizes((25,)) self._paraminsert(cur) # Make sure cursor still works def test_setoutputsize_basic(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: cur.setoutputsize(1000) cur.setoutputsize(2000, 0) self._paraminsert(cur) # Make sure the cursor still works def test_executemany(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: cur.execute("create table booze (name varchar(20))") largs = [("Cooper's",), ("Boag's",)] margs = [{"beer": "Cooper's"}, {"beer": "Boag's"}] cur.executemany("insert into booze values (?)", largs) self.assertEqual( cur.rowcount, 2, "insert using cursor.executemany set cursor.rowcount to " "incorrect value %r" % cur.rowcount, ) cur.execute("select name from booze") res = cur.fetchall() self.assertEqual( len(res), 2, "cursor.fetchall retrieved incorrect number of rows" ) beers = [res[0][0], res[1][0]] beers.sort() self.assertEqual(beers[0], "Boag's", "incorrect data retrieved") self.assertEqual(beers[1], "Cooper's", "incorrect data retrieved") def test_executemanyGenerator(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: def mygen(ls): for i in ls: yield [i] cu.execute("create table booze (name varchar(20))") cu.executemany("insert into booze values (?)", mygen(self.samples)) cu.execute("select * from booze") f = cu.fetchall() for i, v in enumerate(self.samples): self.assertEqual(f[i][0], v) def test_executemanyIterator(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: class myiter: def __init__(self, ls): self.ls = ls self.i = 0 def __iter__(self): return self def __next__(self): if self.i == len(self.ls): raise StopIteration rc = [self.ls[self.i]] self.i += 1 return rc cu.execute("create table booze (name varchar(20))") cu.executemany("insert into booze values (?)", myiter(self.samples)) cu.execute("select * from booze") f = cu.fetchall() for i, v in enumerate(self.samples): self.assertEqual(f[i][0], v) def test_executemanyBad(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table booze (name varchar(20))") with self.assertRaises(TypeError): cu.executemany("insert into booze values (?)", object()) with self.assertRaises(dbapi2.InterfaceError): cu.executemany("insert into booze values (?)", object()) with self.assertRaises(dbapi2.InterfaceError): cu.executemany(object(), []) cu.executemany("insert into booze values (?)", None) with self.assertRaises(dbapi2.ProgrammingError): cu.executemany("inert into booze values (?)", [['?']]) def test_fetchone(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: # cursor.fetchone should raise an Error if called before # executing a select-type query self.assertRaises(dbapi2.ProgrammingError, cur.fetchone) # cursor.fetchone should raise an Error if called after # executing a query that cannot return rows cur.execute("create table booze (name varchar(20))") self.assertRaises(dbapi2.Error, cur.fetchone) cur.execute("select name from booze") self.assertEqual( cur.fetchone(), None, "cursor.fetchone should return None if a query retrieves " "no rows", ) self.assertEqual(cur.rowcount, 0) # cursor.fetchone should raise an Error if called after # executing a query that cannot return rows cur.execute("insert into booze values ('Victoria Bitter')") self.assertRaises(dbapi2.Error, cur.fetchone) cur.execute("select name from booze") r = cur.fetchone() self.assertEqual( len(r), 1, "cursor.fetchone should have retrieved a single row" ) self.assertEqual( r[0], "Victoria Bitter", "cursor.fetchone retrieved incorrect data" ) self.assertEqual( cur.fetchone(), None, "cursor.fetchone should return None if no more rows available", ) self.assertEqual(cur.rowcount, -1) samples = [ "Carlton Cold", "Carlton Draft", "Mountain Goat", "Redback", "Victoria Bitter", "XXXX", ] def _populate(self): """ Return a list of sql commands to setup the DB for the fetch tests. """ populate = [ "insert into booze values ('{}')".format(s) for s in self.samples ] return populate def test_fetchmany(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: # cursor.fetchmany should raise an Error if called without # issuing a query self.assertRaises(dbapi2.ProgrammingError, cur.fetchmany, 4) cur.execute("create table booze (name varchar(20))") for sql in self._populate(): cur.execute(sql) cur.execute("select name from booze") r = cur.fetchmany() self.assertEqual( len(r), 1, "cursor.fetchmany retrieved incorrect number of rows, " "default of arraysize is one.", ) cur.arraysize = 10 r = cur.fetchmany(3) # Should get 3 rows self.assertEqual( len(r), 3, "cursor.fetchmany retrieved incorrect number of rows" ) r = cur.fetchmany(4) # Should get 2 more self.assertEqual( len(r), 2, "cursor.fetchmany retrieved incorrect number of rows" ) r = cur.fetchmany(4) # Should be an empty sequence self.assertEqual( len(r), 0, "cursor.fetchmany should return an empty sequence after " "results are exhausted", ) self.assertEqual(cur.rowcount, -1) # Same as above, using cursor.arraysize cur.arraysize = 4 cur.execute("select name from booze") r = cur.fetchmany() # Should get 4 rows self.assertEqual( len(r), 4, "cursor.arraysize not being honoured by fetchmany" ) r = cur.fetchmany() # Should get 2 more self.assertEqual(len(r), 2) r = cur.fetchmany() # Should be an empty sequence self.assertEqual(len(r), 0) self.assertEqual(cur.rowcount, -1) cur.arraysize = 6 cur.execute("select name from booze") rows = cur.fetchmany() # Should get all rows self.assertTrue(cur.rowcount in (-1, 6)) self.assertEqual(len(rows), 6) self.assertEqual(len(rows), 6) rows = [r[0] for r in rows] rows.sort() # Make sure we get the right data back out for i in range(0, 6): self.assertEqual( rows[i], self.samples[i], "incorrect data retrieved by cursor.fetchmany", ) rows = cur.fetchmany() # Should return an empty list self.assertEqual( len(rows), 0, "cursor.fetchmany should return an empty sequence if " "called after the whole result set has been fetched", ) self.assertEqual(cur.rowcount, -1) cur.execute("create table barflys (name varchar(20))") cur.execute("select name from barflys") r = cur.fetchmany() # Should get empty sequence self.assertEqual( len(r), 0, "cursor.fetchmany should return an empty sequence if " "query retrieved no rows", ) def test_fetchall(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: # cursor.fetchall should raise an Error if called # without executing a query that may return rows (such # as a select) self.assertRaises(dbapi2.Error, cur.fetchall) cur.execute("create table booze (name varchar(20))") for sql in self._populate(): cur.execute(sql) # cursor.fetchall should raise an Error if called # after executing a statement that cannot return rows self.assertRaises(dbapi2.ProgrammingError, cur.fetchall) cur.execute("select name from booze") rows = cur.fetchall() self.assertEqual(cur.rowcount, -1) self.assertEqual( len(rows), len(self.samples), "cursor.fetchall did not retrieve all rows", ) rows = [r[0] for r in rows] rows.sort() for i in range(0, len(self.samples)): self.assertEqual( rows[i], self.samples[i], "cursor.fetchall retrieved incorrect rows" ) rows = cur.fetchall() self.assertEqual( len(rows), 0, "cursor.fetchall should return an empty list if called " "after the whole result set has been fetched", ) self.assertEqual(cur.rowcount, -1) cur.execute("create table barflys (name varchar(20))") cur.execute("select name from barflys") rows = cur.fetchall() self.assertEqual(cur.rowcount, 1) self.assertEqual( len(rows), 0, "cursor.fetchall should return an empty list if " "a select query returns no rows", ) def test_mixedfetch(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: cur.execute("create table booze (name varchar(20))") for sql in self._populate(): cur.execute(sql) cur.execute("select name from booze") self.assertEqual(cur.rowcount, -1) rows1 = cur.fetchone() rows23 = cur.fetchmany(2) rows4 = cur.fetchone() rows56 = cur.fetchall() self.assertEqual(cur.rowcount, -1) self.assertEqual( len(rows23), 2, "fetchmany returned incorrect number of rows" ) self.assertEqual( len(rows56), 2, "fetchall returned incorrect number of rows" ) rows = [rows1[0]] rows.extend([rows23[0][0], rows23[1][0]]) rows.append(rows4[0]) rows.extend([rows56[0][0], rows56[1][0]]) rows.sort() for i in range(0, len(self.samples)): self.assertEqual( rows[i], self.samples[i], "incorrect data retrieved or inserted" ) def test_nextset(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table booze (name varchar(20))") booze = ["Wiskey", ] cu.execute("insert into booze(name) values (?)", booze) self.assertEqual(cu.rowcount, 1) cu.execute("select * from booze; select * from booze") self.assertEqual(cu.fetchone(), booze) nxt = cu.nextset() self.assertTrue(nxt in (True, None)) # H2 does not support multiple result sets if nxt: self.assertEqual(cu.fetchone(), booze) @common.unittest.skip def test_lastrowid(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table booze(id INTEGER IDENTITY PRIMARY KEY, name varchar(255))") cu.execute("insert into booze(name) values('hello')", keys=True) id0 = cu.lastrowid self.assertIsInstance(id0, int) # Call more than once id1 = cu.lastrowid self.assertIsInstance(id1, int) cx.commit() cu.execute("insert into booze(name) values('there')", keys=True) id2 = cu.lastrowid self.assertIsInstance(id2, int) cu.execute("select * from booze") f = cu.fetchall() self.assertEqual(cu.lastrowid, None) # sqlite has weird behaviors self.assertEqual(f[0][0], id0) self.assertEqual(f[1][0], id2) @common.unittest.skip def test_lastrowidMany(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table booze(id INTEGER IDENTITY PRIMARY KEY, name varchar(255))") cu.executemany("insert into booze(name) values(?)", [['Redback'], ['Fat Yak']], keys=True) ids = cu.lastrowid self.assertIsInstance(ids, list) self.assertEqual(len(ids), 2) cu.execute("select * from booze") f = cu.fetchall() self.assertEqual(f[0][0], ids[0]) self.assertEqual(f[1][0], ids[1]) def test_iter(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: ls = [['Tooheys Old'], ['Nine Tales Original Amber Ale'], ['Dogbolter']] cu.execute("create table booze(name varchar(255))") cu.executemany("insert into booze(name) values(?)", ls, keys=True) # make sure we throw if there is no result set with self.assertRaises(dbapi2.ProgrammingError): for booze in cu: pass cu.execute("select * from booze") for i, booze in enumerate(cu): self.assertEqual(ls[i], booze) def testNoAdapter(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table booze(name varchar(50))") with self.assertRaises(dbapi2.InterfaceError): cu.execute("insert into booze(name) values(?)", [object()]) def testBadParameters(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table booze(name varchar(50))") with self.assertRaises(dbapi2.InterfaceError): cu.execute("insert into booze(name) values(?)", object()) def test_callproc(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: with self.assertRaises(dbapi2.ProgrammingError): r = cu.callproc("lower", ("FOO",)) @common.unittest.skip def test_callprocBad(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: with self.assertRaises(dbapi2.ProgrammingError): r = cu.callproc("not_there", ("FOO",)) with self.assertRaises(dbapi2.InterfaceError): r = cu.callproc(object(), ("FOO",)) with self.assertRaises(dbapi2.InterfaceError): r = cu.callproc("lower", (object(),)) with self.assertRaises(dbapi2.InterfaceError): r = cu.callproc("lower", object()) def test_close(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.close() with self.assertRaises(dbapi2.ProgrammingError): cu.close() def test_parameters(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: with self.assertRaises(dbapi2.ProgrammingError): p = cu.parameters cu.execute("create table booze(name varchar(50))") cu.execute("insert into booze(name) values(?)", ('Hahn Super Dry',)) p = cu.parameters self.assertEqual(p[0][0:2], ('VARCHAR', dbapi2.VARCHAR)) def test_resultSet(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table booze(name varchar(50))") cu.execute("insert into booze(name) values(?)", ('Hahn Super Dry',)) cu.execute("select * from booze") rs = cu.resultSet self.assertIsInstance(rs, java.sql.ResultSet) def test_fetchClosed(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table booze(name varchar(50))") cu.execute("insert into booze(name) values(?)", ('Hahn Super Dry',)) cu.execute("select * from booze") cu.close() with self.assertRaises(dbapi2.ProgrammingError): cu.fetchone() with self.assertRaises(dbapi2.ProgrammingError): cu.fetchmany() with self.assertRaises(dbapi2.ProgrammingError): cu.fetchall() self.assertEqual(cu.resultSet, None) def test_executeBadParameters(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: def mygen(ls): for i in ls: yield i cu.execute("create table booze(name varchar(50), price integer)") with self.assertRaises(dbapi2.ProgrammingError): cu.executemany("insert into booze(name,price) values(?,?)", [('Hahn Super Dry', 2), ('Coors',)]) with self.assertRaises(dbapi2.InterfaceError): cu.execute("insert into booze(name,price) values(?,?)", {'name': 'Budweiser', 'price': 10}) with self.assertRaises(dbapi2.ProgrammingError): cu.executemany("insert into booze(name,price) values(?,?)", mygen([['Budweiser']])) cu.execute("insert into booze(name,price) values(?,?)", mygen(['Pabst Blue Robot', 20000])) with self.assertRaises(dbapi2.ProgrammingError): cu.execute("insert into booze(name,price) values(?,?)", mygen(['Budweiser'])) with self.assertRaises(dbapi2.InterfaceError): cu.execute("insert into booze(name,price) values(?,?)", 'Budweiser') with self.assertRaises(dbapi2.ProgrammingError): cu.execute("insert into booze(name,price) values(?,?)", mygen(['Budweiser', 2, 'no'])) with self.assertRaises(dbapi2.InterfaceError): cu.execute("insert into booze(name,price) values(?,?)", object()) class AdapterTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) if common.fast: raise common.unittest.SkipTest("fast") self.testdata = b"abcdefg" * 10 self.params = memoryview(zlib.compress(self.testdata)) def tearDown(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: try: cur.execute("drop table test") except dbapi2.Error: pass def testOnConnector(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name varchar(255))") cx.adapters[object] = lambda x: "none" cu.execute("insert into test(name) values(?)", [object()]) cu.execute("select * from test") f = cu.fetchall() self.assertEqual(f[0][0], "none") @common.unittest.skipUnless(zlib, "requires zlib") class ConverterTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) if common.fast: raise common.unittest.SkipTest("fast") self.testdata = b"abcdefg" * 10 self.params = memoryview(zlib.compress(self.testdata)) def tearDown(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: try: cur.execute("drop table test") except dbapi2.Error: pass @staticmethod def convert(s): return zlib.decompress(s) def testConvertersBad(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name varchar(20))") cu.executemany("insert into test(name) values(?)", [['alice'], ['bob'], ['charlie']]) cu.execute("select name from test") with self.assertRaises(dbapi2.ProgrammingError): cu.fetchone(converters=[]) cu.execute("select name from test") with self.assertRaises(dbapi2.InterfaceError): cu.fetchone(converters=[int]) cu.execute("select name from test") with self.assertRaises(dbapi2.ProgrammingError): cu.fetchone(converters=[str, str]) def testConvertersNone(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name varchar(20))") cu.executemany("insert into test(name) values(?)", [['alice'], ['bob'], ['charlie']]) cu.execute("select name from test") f = cu.fetchone(converters=None) self.assertIsInstance(f[0], java.lang.String) cu.execute("select name from test") def testConvertersPositional(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name varchar(20))") cu.executemany("insert into test(name) values(?)", [['alice'], ['bob'], ['charlie']]) cu.execute("select name from test") f = cu.fetchone(converters=[str]) self.assertIsInstance(f[0], str) cu.execute("select name from test") def test_fetchoneTypesPositional(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name varchar(20))") cu.executemany("insert into test(name) values(?)", [['alice'], ['bob'], ['charlie']]) cu.execute("select name from test") f = cu.fetchone(types=[dbapi2.STRING]) self.assertIsInstance(f[0], str) def test_fetchmanyTypesPositional(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name varchar(20))") cu.executemany("insert into test(name) values(?)", [['alice'], ['bob'], ['charlie']]) cu.execute("select name from test") f = cu.fetchmany(types=[dbapi2.STRING]) self.assertIsInstance(f[0][0], str) def test_fetchallTypesPositional(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name varchar(20))") cu.executemany("insert into test(name) values(?)", [['alice'], ['bob'], ['charlie']]) cu.execute("select name from test") f = cu.fetchall(types=[dbapi2.STRING]) self.assertIsInstance(f[0][0], str) def testTypesPositionalBAD(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name varchar(20))") cu.executemany("insert into test(name) values(?)", [['alice'], ['bob'], ['charlie']]) cu.execute("select name from test") with self.assertRaises(dbapi2.ProgrammingError): f = cu.fetchone(types=[dbapi2.STRING, dbapi2.STRING]) with self.assertRaises(dbapi2.ProgrammingError): f = cu.fetchone(types=[]) class GettersTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) if common.fast: raise common.unittest.SkipTest("fast") self.testdata = b"abcdefg" * 10 self.params = memoryview(zlib.compress(self.testdata)) def tearDown(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: try: cur.execute("drop table test") except dbapi2.Error: pass @common.unittest.skip class TransactionsTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) if common.fast: raise common.unittest.SkipTest("fast") def tearDown(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: try: cur.execute("drop table test") except dbapi2.Error: pass def testTransactionRollbackCreate(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cx.commit() # needed before starting transactions cu.execute("begin") cu.execute("create table test(name VARCHAR(10))") cx.rollback() # with self.assertRaises(dbapi2.ProgrammingError): cu.execute("select * from test") def testTransactionRollbackInsert(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cx.commit() # needed before starting transactions cu.execute("create table test(name VARCHAR(10))") cx.commit() cu.execute("begin") cu.execute("insert into test(name) values('alice')") cx.rollback() # Alice should go away result = cu.execute("select * from test").fetchall() self.assertEqual(result, []) def testTransactionRollbackClose(self): with dbapi2.connect(db_name) as cx2: with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cx.commit() # needed before starting transactions cu.execute("create table test(name VARCHAR(10))") cu.execute("insert into test(name) values('alice')") cx.commit() cu.execute("begin") cu.execute("insert into test(name) values('bob')") result = cu.execute("select * from test").fetchall() self.assertEqual(result, [['alice'], ['bob']]) # Bob should go away with cx2.cursor() as cu: result = cu.execute("select * from test").fetchall() self.assertEqual(result, [['alice']]) class TypeTestCase(common.JPypeTestCase): """ This test is db dependent, but needed to check all code paths. """ def setUp(self): common.JPypeTestCase.setUp(self) if common.fast: raise common.unittest.SkipTest("fast") def tearDown(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: try: cur.execute("drop table test") except dbapi2.Error: pass def testTime(self): with dbapi2.connect(db_name, getters=dbapi2.GETTERS_BY_NAME) as cx, cx.cursor() as cu: cu.execute("create table test(NAME TIME)") cu.execute("select * from test") t1 = jpype.java.sql.Time(1, 2, 3) cu.execute("insert into test(NAME) values(?)", [t1]) f = cu.execute('select * from test').fetchone() self.assertIsInstance(f[0], datetime.time) cu.execute("delete from test") cu.execute("insert into test(NAME) values(?)", f) f2 = cu.execute('select * from test').fetchone() self.assertEqual(f2, f) cu.execute("delete from test") # Test with Java t1 = jpype.java.sql.Time(1, 2, 3) cu.execute("insert into test(NAME) values(?)", [t1]) f3 = cu.execute('select * from test').fetchone() self.assertEqual(f3[0], datetime.time(1, 2, 3)) f4 = cu.execute('select * from test').fetchone(converters=None) self.assertEqual(f4[0], t1) self.assertIsInstance(f4[0], jpype.java.sql.Time) cu.execute("delete from test") # Test with dbapi2.Time t1 = dbapi2.Time(6, 21, 32) cu.execute("insert into test(NAME) values(?)", [t1]) f3 = cu.execute('select * from test').fetchone() self.assertEqual(f3[0], datetime.time(6, 21, 32)) def testDate(self): with dbapi2.connect(db_name, getters=dbapi2.GETTERS_BY_NAME) as cx, cx.cursor() as cu: cu.execute("create table test(NAME DATE)") cu.execute("select * from test") t1 = java.sql.Date(2012 - 1900, 2 - 1, 5) cu.execute("insert into test(NAME) values(?)", [t1]) #cu.execute("insert into test(NAME) values('2012-02-05')") f = cu.execute('select * from test').fetchone() self.assertIsInstance(f[0], datetime.date) cu.execute("delete from test") cu.execute("insert into test(NAME) values(?)", f) f2 = cu.execute('select * from test').fetchone() self.assertEqual(f2, f) cu.execute("delete from test") # Test with Java t1 = java.sql.Date(1972 - 1900, 4 - 1, 1) cu.execute("insert into test(NAME) values(?)", [t1]) f3 = cu.execute('select * from test').fetchone() self.assertEqual(f3[0], datetime.date(1972, 4, 1)) f4 = cu.execute('select * from test').fetchone(converters=None) self.assertEqual(f4[0], t1) self.assertIsInstance(f4[0], java.sql.Date) cu.execute("delete from test") # Test with dbapi2.Date t1 = dbapi2.Date(2020, 5, 21) cu.execute("insert into test(NAME) values(?)", [t1]) f3 = cu.execute('select * from test').fetchone() self.assertEqual(f3[0], datetime.date(2020, 5, 21)) def testTimestamp(self): with dbapi2.connect(db_name, getters=dbapi2.GETTERS_BY_NAME) as cx, cx.cursor() as cu: cu.execute("create table test(NAME TIMESTAMP)") cu.execute("select * from test") cu.execute("insert into test(NAME) values('2012-02-05 12:02:45.123')") f = cu.execute('select * from test').fetchone() self.assertIsInstance(f[0], datetime.date) cu.execute("delete from test") cu.execute("insert into test(NAME) values(?)", f) f2 = cu.execute('select * from test').fetchone() self.assertEqual(f2, f) cu.execute("delete from test") # Test with Java t1 = java.sql.Timestamp(1972 - 1900, 4 - 1, 1, 12, 2, 45, 123000000) cu.execute("insert into test(NAME) values(?)", [t1]) f3 = cu.execute('select * from test').fetchone() self.assertEqual(f3[0], datetime.datetime(1972, 4, 1, 12, 2, 45, 123000)) f4 = cu.execute('select * from test').fetchone(converters=None) self.assertEqual(f4[0], t1) self.assertIsInstance(f4[0], java.sql.Timestamp) cu.execute("delete from test") # Test with dbapi2.Date t1 = dbapi2.Timestamp(2020, 5, 21, 3, 4, 5, 123000000) cu.execute("insert into test(NAME) values(?)", [t1]) f3 = cu.execute('select * from test').fetchone() self.assertEqual(f3[0], datetime.datetime(2020, 5, 21, 3, 4, 5, 123000)) def _testInt(self, tp, desc, jtype, null=True): with dbapi2.connect(db_name, getters=dbapi2.GETTERS_BY_NAME) as cx, cx.cursor() as cu: cu.execute("create table test(NAME %s)" % tp) cu.execute("insert into test(NAME) values(?)", [123]) f = cu.execute("select * from test").fetchone() self.assertEqual(f[0], 123) self.assertIsInstance(f[0], int) self.assertEqual(cu.description[0][0:2], desc) f = cu.execute("select * from test").fetchone(converters=None) self.assertEqual(f[0], 123) self.assertIsInstance(f[0], jtype) cu.execute("delete from test") if null: cu.execute("insert into test(NAME) values(?)", [None]) f = cu.execute("select * from test").fetchone(converters=None) self.assertEqual(f[0], None) def testTinyInt(self): self._testInt('TINYiNT', ('NAME', 'TINYINT'), jpype.JShort) def testBigInt(self): self._testInt('BIGINT', ('NAME', 'BIGINT'), jpype.JLong) def testIdentity(self): self._testInt('IDENTITY', ('NAME', 'IDENTITY'), jpype.JInt, False) def testInteger(self): self._testInt('INTEGER', ('NAME', 'INTEGER'), jpype.JInt) def testSmallInt(self): self._testInt('SMALLINT', ('NAME', 'SMALLINT'), jpype.JShort) def _testFloat(self, tp, desc, jtype): with dbapi2.connect(db_name, getters=dbapi2.GETTERS_BY_NAME) as cx, cx.cursor() as cu: cu.execute("create table test(NAME %s)" % tp) cu.execute("insert into test(NAME) values(?)", [1.25]) f = cu.execute("select * from test").fetchone() self.assertEqual(f[0], 1.25) self.assertIsInstance(f[0], float) self.assertEqual(cu.description[0][0:2], desc) f = cu.execute("select * from test").fetchone(converters=None) self.assertEqual(f[0], 1.25) self.assertIsInstance(f[0], jtype) cu.execute("delete from test") cu.execute("insert into test(NAME) values(?)", [None]) f = cu.execute("select * from test").fetchone(converters=None) self.assertEqual(f[0], None) def testFloat(self): self._testFloat('FLOAT', ('NAME', 'FLOAT'), jpype.JDouble) def testDouble(self): self._testFloat('DOUBLE', ('NAME', 'DOUBLE'), jpype.JDouble) def testReal(self): self._testFloat('REAL', ('NAME', 'REAL'), jpype.JFloat) def _testNumeric(self, tp, desc, jtype): with dbapi2.connect(db_name, getters=dbapi2.GETTERS_BY_NAME) as cx, cx.cursor() as cu: cu.execute("create table test(NAME %s(5,2))" % tp) cu.execute("insert into test(NAME) values(?)", [1.25]) f = cu.execute("select * from test").fetchone() self.assertEqual(f[0], 1.25) self.assertIsInstance(f[0], decimal.Decimal) self.assertEqual(cu.description[0][0:2], desc) f = cu.execute("select * from test").fetchone(converters=None) self.assertEqual(f[0], decimal.Decimal(1.25)) self.assertIsInstance(f[0], jtype) cu.execute("delete from test") cu.execute("insert into test(NAME) values(?)", [None]) f = cu.execute("select * from test").fetchone(converters=None) self.assertEqual(f[0], None) def testNumeric(self): self._testNumeric('NUMERIC', ('NAME', 'NUMERIC'), java.math.BigDecimal) def testDecimal(self): self._testNumeric('DECIMAL', ('NAME', 'DECIMAL'), java.math.BigDecimal) def _testBinary(self, tp, desc, jtype): with dbapi2.connect(db_name, getters=dbapi2.GETTERS_BY_NAME) as cx, cx.cursor() as cu: cu.execute("create table test(NAME %s)" % tp) v = bytes([1, 2, 3]) cu.execute("insert into test(NAME) values(?)", [v]) f = cu.execute("select * from test").fetchone() self.assertEqual(f[0], v) self.assertIsInstance(f[0], bytes) self.assertEqual(cu.description[0][0:2], desc) f = cu.execute("select * from test").fetchone(converters=None) self.assertEqual(bytes(f[0]), v) self.assertIsInstance(f[0], jtype) cu.execute("delete from test") cu.execute("insert into test(NAME) values(?)", [None]) f = cu.execute("select * from test").fetchone(converters=None) self.assertEqual(f[0], None) def testBinary(self): self._testBinary('BINARY(3)', ('NAME', 'BINARY'), JArray(JByte)) def testBlob(self): self._testBinary('BLOB', ('NAME', 'BLOB'), JArray(JByte)) def testLongVarBinary(self): self._testBinary('LONGVARBINARY', ('NAME', 'LONGVARBINARY'), JArray(JByte)) def testVarBinary(self): self._testBinary('VARBINARY(10)', ('NAME', 'VARBINARY'), JArray(JByte)) def _testChars(self, tp, desc, jtype, v="hello"): with dbapi2.connect(db_name, getters=dbapi2.GETTERS_BY_NAME) as cx, cx.cursor() as cu: cu.execute("create table test(NAME %s)" % tp) cu.execute("insert into test(NAME) values(?)", [v]) f = cu.execute("select * from test").fetchone() self.assertEqual(f[0], v) self.assertIsInstance(f[0], str) self.assertEqual(cu.description[0][0:2], desc) f = cu.execute("select * from test").fetchone(converters=None) self.assertEqual(f[0], v) self.assertIsInstance(f[0], jtype) cu.execute("delete from test") cu.execute("insert into test(NAME) values(?)", [None]) f = cu.execute("select * from test").fetchone(converters=None) self.assertEqual(f[0], None) def testChar(self): self._testChars('CHAR', ('NAME', 'CHAR'), java.lang.String, 'a') def testVarChar(self): self._testChars('VARCHAR', ('NAME', 'VARCHAR'), java.lang.String) def testLongVarChar(self): self._testChars('LONGVARCHAR', ('NAME', 'LONGVARCHAR'), java.lang.String) def testClob(self): self._testChars('CLOB', ('NAME', 'CLOB'), java.lang.String) def testBoolean(self): with dbapi2.connect(db_name, getters=dbapi2.GETTERS_BY_NAME) as cx, cx.cursor() as cu: cu.execute("create table test(NAME BOOLEAN)") cu.execute("insert into test(NAME) values(?)", [True]) f = cu.execute("select * from test").fetchone() self.assertEqual(f[0], True) self.assertIsInstance(f[0], int) self.assertEqual(cu.description[0][0:2], ('NAME', 'BOOLEAN')) f = cu.execute("select * from test").fetchone(converters=None) self.assertEqual(f[0], True) self.assertIsInstance(f[0], type(True)) cu.execute("delete from test") cu.execute("insert into test(NAME) values(?)", [None]) f = cu.execute("select * from test").fetchone(converters=None) self.assertEqual(f[0], None) class OtherTestCase(common.JPypeTestCase): """ This test is db dependent, but needed to check all code paths. """ def setUp(self): common.JPypeTestCase.setUp(self) if common.fast: raise common.unittest.SkipTest("fast") def tearDown(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: try: cur.execute("drop table test") except dbapi2.Error: pass def testJSON(self): got = [] class MyType(dbapi2.JDBCType): def get(self, rs, column, st): got.append(column) return dbapi2.JDBCType.get(self, rs, column, st) # Register a new type JSON = MyType("JSON", None) with dbapi2.connect(db_name, getters=dbapi2.GETTERS_BY_NAME) as cx, cx.cursor() as cu: cu.execute("create table test(name JSON)") cu.execute("insert into test(name) values('{age: 31}')") f = cu.execute("select * from test").fetchone() self.assertEqual(got, [1]) del dbapi2._registry[JSON] class ThreadingTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) if common.fast: raise common.unittest.SkipTest("fast") def tearDown(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cur: try: cur.execute("drop table test") except dbapi2.Error: pass def _testThread(self, cu, cmd, args, exc): error = [] def run(): try: cmd(*args) except Exception as ex: error.append(ex) t = threading.Thread(target=run) t.start() t.join() self.assertEqual(len(error), 1) with self.assertRaises(exc): raise error[0] def test_execute(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name VARCHAR(10))") self._testThread(cu, cu.execute, ("insert into test(name) values ('a')",), dbapi2.ProgrammingError) def test_executemany(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name VARCHAR(10))") self._testThread(cu, cu.executemany, ("insert into test(name) values ('?')", [[1]]), dbapi2.ProgrammingError) def test_fetchone(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name VARCHAR(10))") cu.execute("insert into test(name) values('a')") self._testThread(cu, cu.fetchone, (), dbapi2.ProgrammingError) def test_fetchmany(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name VARCHAR(10))") cu.execute("insert into test(name) values('a')") self._testThread(cu, cu.fetchmany, (), dbapi2.ProgrammingError) def test_fetchall(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name VARCHAR(10))") cu.execute("insert into test(name) values('a')") self._testThread(cu, cu.fetchall, (), dbapi2.ProgrammingError) def test_close(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name VARCHAR(10))") cu.execute("insert into test(name) values('a')") self._testThread(cu, cu.close, (), dbapi2.ProgrammingError) @common.unittest.skip def test_callproc(self): with dbapi2.connect(db_name) as cx, cx.cursor() as cu: cu.execute("create table test(name VARCHAR(10))") cu.execute("insert into test(name) values('a')") self._testThread(cu, cu.callproc, ("lower", ["FOO"]), dbapi2.ProgrammingError) jpype-1.3.0/test/jpypetest/test_startup.py000066400000000000000000000066351405671516700210110ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import jpype import common import subrun import os import sys import unittest def runStartJVM(*args, **kwargs): jpype.startJVM(*args, **kwargs) def runStartJVMTest(*args, **kwargs): jpype.startJVM(*args, **kwargs) try: jclass = jpype.JClass('jpype.array.TestArray') return except: pass raise RuntimeError("Test class not found") root = os.path.dirname(os.path.abspath(os.path.dirname(__file__))) cp = os.path.join(root, 'classes').replace('\\', '/') @subrun.TestCase(individual=True) class StartJVMCase(unittest.TestCase): def setUp(self): self.jvmpath = jpype.getDefaultJVMPath() def testStartup(self): with self.assertRaises(OSError): jpype.startJVM(convertStrings=False) jpype.startJVM(convertStrings=False) def testRestart(self): with self.assertRaises(OSError): jpype.startJVM(convertStrings=False) jpype.shutdownJVM() jpype.startJVM(convertStrings=False) def testJVMPathKeyword(self): runStartJVM(jvmpath=self.jvmpath) def testInvalidArgsFalse(self): with self.assertRaises(RuntimeError): runStartJVM("-for_sure_InVaLiD", ignoreUnrecognized=False, convertStrings=False) def testInvalidArgsTrue(self): runStartJVM("-for_sure_InVaLiD", ignoreUnrecognized=True, convertStrings=False) def testClasspathArgKeyword(self): runStartJVMTest(classpath=cp, convertStrings=False) def testClasspathArgList(self): runStartJVMTest(classpath=[cp], convertStrings=False) def testClasspathArgListEmpty(self): runStartJVMTest(classpath=[cp, ''], convertStrings=False) def testClasspathArgDef(self): runStartJVMTest('-Djava.class.path=%s' % cp, convertStrings=False) def testClasspathTwice(self): with self.assertRaises(TypeError): runStartJVMTest('-Djava.class.path=%s' % cp, classpath=cp, convertStrings=False) def testClasspathBadType(self): with self.assertRaises(TypeError): runStartJVMTest(classpath=1, convertStrings=False) def testPathArg(self): runStartJVMTest(self.jvmpath, classpath=cp, convertStrings=False) def testPathKeyword(self): path = jpype.getDefaultJVMPath() runStartJVMTest(classpath=cp, jvmpath=self.jvmpath, convertStrings=False) def testPathTwice(self): with self.assertRaises(TypeError): jpype.startJVM(self.jvmpath, jvmpath=self.jvmpath) def testBadKeyword(self): with self.assertRaises(TypeError): jpype.startJVM(invalid=True) jpype-1.3.0/test/jpypetest/test_synchronized.py000066400000000000000000000051501405671516700220150ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import sys import threading import time import jpype from jpype import synchronized import common fail = False if fail: # Cause a fail class _JMonitor(object): def __init__(self, obj): pass def __enter__(self): pass def __exit__(self, exception_type, exception_value, traceback): pass def synchronized(obj): return _JMonitor(obj) success = True glob = 0 obj = None class MyThread(threading.Thread): def run(self): global glob, success, obj with synchronized(obj): # Increment the global resource glob += 1 # Wait for a while time.sleep(0.1) # If anything else accessed then it was a fail if glob != 1: success = False # Decrement the global resoure glob -= 1 class SynchronizedTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) global glob, success, obj obj = jpype.JClass("java.lang.Object")() def testSynchronized(self): global glob, success glob = 0 success = True tl = [] # Create 10 threads trying to access the same resource for i in range(0, 10): tl.append(MyThread()) # Release them at the same time for i in tl: i.start() # Wait for all to finish for i in tl: i.join() # Verify they did not trample each other self.assertTrue(success) def testSyncronizedFail(self): with self.assertRaisesRegex(TypeError, "Java object is required"): with jpype.synchronized(object()): pass with self.assertRaisesRegex(TypeError, "Java primitives cannot be used"): with jpype.synchronized(jpype.JInt(1)): pass jpype-1.3.0/test/jpypetest/test_thread.py000066400000000000000000000045101405671516700205440ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import jpype import sys import time import common import pytest class ThreadTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) @pytest.mark.filterwarnings("ignore::DeprecationWarning") def testAttach(self): # Make sure we are attached to start the test jpype.attachThreadToJVM() self.assertTrue(jpype.isThreadAttachedToJVM()) # Detach from the thread jpype.detachThreadFromJVM() self.assertFalse(jpype.isThreadAttachedToJVM()) # Reattach to the thread jpype.attachThreadToJVM() self.assertTrue(jpype.isThreadAttachedToJVM()) # Detach again jpype.detachThreadFromJVM() self.assertFalse(jpype.isThreadAttachedToJVM()) # Call a Java method which will cause it to attach automatically s = jpype.JString("foo") self.assertTrue(jpype.isThreadAttachedToJVM()) def testAttachNew(self): import java # Detach the thread java.lang.Thread.detach() self.assertFalse(java.lang.Thread.isAttached()) # Attach as a main thread java.lang.Thread.attach() self.assertTrue(java.lang.Thread.isAttached()) self.assertFalse(java.lang.Thread.currentThread().isDaemon()) # Detach the thread java.lang.Thread.detach() self.assertFalse(java.lang.Thread.isAttached()) # Attach as a daemon thread java.lang.Thread.attachAsDaemon() self.assertTrue(java.lang.Thread.isAttached()) self.assertTrue(java.lang.Thread.currentThread().isDaemon()) jpype-1.3.0/test/jpypetest/test_utf8.py000066400000000000000000000207141405671516700201670ustar00rootroot00000000000000# -*- coding: utf-8 -*- # ***************************************************************************** # Copyright 2018 Rene Bakker # ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** ''' Test communication with jpype using 4-byte utf-8 characters (emoji) IMPORTANT: The routines have only be tested in Python3. Given the difference in string handling between Python2 and Python3, it is not likely this routines have any significance for Python2. The following tests are defined: General: 1. Test if the java class (jpype.utf8.Utf8Test) can return the default ASCII string. 2. Pass an ASCII string to the java test class and check if it remained unchanged when returned from java. Binary: python strings are injected into java.lang.String in binary format with str.encode() 3. Pass a series of reference UTF-8 strings and compare them with the reference strings in the java class. 4. Pass a series of reference UTF-8 strings and check if they remained unchanged when returned from Java. Allow for surrogate substitution in the utf-16 strings returned from Java. 5. Pass a series of reference UTF-8 strings and check if they remained unchanged when returned from Java. Use the python default strict encoding rules for the returned string. Navive strings: python strings are passed as-is into a java method, wich accepts String as argument 6. Pass a series of reference UTF-8 strings and compare them with the reference strings in the java class. 7. Pass a series of reference UTF-8 strings and check if they remained unchanged when returned from Java. Allow for surrogate substitution in the utf-16 strings returned from Java. 8. Pass a series of reference UTF-8 strings and check if they remained unchanged when returned from Java. Use the python default strict encoding rules for the returned string. At the time if writing: Passed tests: 1, 2, 3, and 4 Failed tests: 5. encoding error returned string 6. uploaded string mutilated for emoji 7. follow-up of 6: mutilated string returned to python (emoji only= 8. idem 7. Note on encoding errors: UnicodeEncodeError: 'utf-8' codec can't encode characters in position xxx-xxx: surrogates not allowed ''' import sys from jpype.types import * import common class Utf8TestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) # Java IO test class self.Utf8Test = JClass('jpype.utf8.Utf8Test') # Test strings # IMPORTANT: they should be identical, and in the same order, as the test strings difned in the # java class Utf8Test self.TDICT = [] self.TDICT.append(['english', ("I can eat glass and it doesn't hurt me.")]) self.TDICT.append(['french', ("Je peux manger du verre, ça ne me fait pas mal.")]) self.TDICT.append(['rune', ("ᛖᚴ ᚷᛖᛏ ᛖᛏᛁ ᚧ ᚷᛚᛖᚱ ᛘᚾ ᚦᛖᛋᛋ ᚨᚧ ᚡᛖ ᚱᚧᚨ ᛋᚨᚱ")]) self.TDICT.append(['cn_simp', ("人人生而自由,在尊严和权利上一律平等。他们赋有理性和良心,并应以兄弟关系的精神互相对待。")]) self.TDICT.append(['cn_trad', ("人人生而自由﹐在尊嚴和權利上一律平等。他們賦有理性和良心﹐並應以兄弟關係的精神互相對待。")]) self.TDICT.append(['arab', ("أنا قادر على أكل الزجاج و هذا لا يؤلمني.")]) self.TDICT.append(['emoji', ("😁😂😃😄😅😆😠😡😢😣😤😥😨😩😪🚉🚌🚏🚑🚒🚓🚕🚗🚙🚚🚢🚤🚥🚧🚨🚻🚼🚽🚾🛀🆕🆖🆗🆘🆙🆚🈁🈂🈚🈯🈹🈺🉐🉑8⃣9⃣7⃣6⃣1⃣0")]) def test_get_ascii(self): """ Test if the default string returns from the java test class. """ utf8_test = self.Utf8Test() self.assertEqual("Utf8Test pure ASCII", utf8_test.get(), "Utf8Test.java default string") def test_ascii_upload(self): """ Test uploading and downloading of a simple ASCII string. """ test_string = 'Python Utf8Test ascii test string' utf8_test = self.Utf8Test(test_string) self.assertEqual(test_string, utf8_test.get(), "Utf8Test.java uploaded ASCII string") def test_binary_upload(self): """ Test binary upload and check in Java if the strings are correct. Assumes synchronized test strings in the java class and in this test class. """ String = JClass('java.lang.String') indx = 0 for lbl, val in self.TDICT: utf8_test = self.Utf8Test(String(val.encode('utf-8'), 'UTF8')) self.assertTrue(utf8_test.equalsTo(indx), "Utf8Test.java binary upload %d (%s) = %s" % (indx, lbl, val)) indx += 1 def test_binary_upload_with_surrogates(self): """ Test binary upload and download of utf strings. Allow for surrogate unicode substitution of the return value. """ String = JClass('java.lang.String') for lbl, val in self.TDICT: utf8_test = self.Utf8Test(String(val.encode('utf-8'), 'UTF8')) try: rval = str(utf8_test.get()).encode( 'utf-16').decode('utf-16') except UnicodeEncodeError as uue: rval = str(utf8_test.get()).encode( 'utf-16', errors='surrogatepass').decode('utf-16') lbl += (' ' + str(uue)) self.assertEqual( val, rval, "Utf8Test.java binary upload with surrogate substitution for: " + lbl) def test_binary_upload_no_surrogates(self): """ Test pure binary upload and download of utf strings. """ String = JClass('java.lang.String') for lbl, val in self.TDICT: utf8_test = self.Utf8Test(String(val.encode('utf-8'), 'UTF8')) self.assertEqual(val, str(utf8_test.get()), "Utf8Test.java binary upload for: " + lbl) def test_string_upload(self): """ Test binary upload and check in Java if the strings are correct. Assumes synchronized test strings in the java class and in this test class. """ indx = 0 for lbl, val in self.TDICT: utf8_test = self.Utf8Test(val) self.assertTrue(utf8_test.equalsTo( indx), "Utf8Test.java binary upload: indx %d = %s" % (indx, lbl)) indx += 1 def test_string_upload_with_surrogates(self): """ Test python string upload and download of utf strings. Allow for surrogate unicode substitution of the return value. """ for lbl, val in self.TDICT: utf8_test = self.Utf8Test(val) try: rval = str(utf8_test.get()).encode( 'utf-16').decode('utf-16') except UnicodeEncodeError as uue: rval = str(utf8_test.get()).encode( 'utf-16', errors='surrogatepass').decode('utf-16') lbl += (' ' + str(uue)) self.assertEqual( val, rval, "Utf8Test.java string upload with surrogate substitution for: " + lbl) def test_string_upload_no_surrogates(self): """ Test pure python string upload and download of utf strings. """ for lbl, val in self.TDICT: utf8_test = self.Utf8Test(val) res = str(utf8_test.get()) self.assertEqual( val, res, "Utf8Test.java string upload for: " + lbl) jpype-1.3.0/test/jpypetest/test_varargs.py000066400000000000000000000113401405671516700207410ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import sys import jpype import common def compareList(l1, l2): if len(l1) != len(l2): return False for i in range(0, len(l1)): if l1[i] != l2[i]: return False return True class VarArgsTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) self.VarArgs = jpype.JClass('jpype.varargs.VarArgs') self.Object = jpype.JClass('java.lang.Object') self.ObjectA = jpype.JArray(self.Object) self.Integer = jpype.JClass('java.lang.Integer') self.String = jpype.JClass('java.lang.String') self.StringA = jpype.JArray(self.String) def testConflict(self): m = jpype.java.util.LinkedHashMap({"a": 1, "b": 2, "c": 3}) test = self.VarArgs() self.assertEqual(test.conflict2([1, 2, 3]), 1) self.assertEqual(test.conflict2(m, m), 2) self.assertEqual(test.conflict3(['h', 'e']), 1) self.assertEqual(test.conflict3('h'), 2) self.assertEqual(test.conflict3('hello'), 2) self.assertEqual(test.conflict1(1), 1) self.assertEqual(test.conflict1([1, 2, 3]), 1) self.assertEqual(test.conflict1({"a": 1, "b": 2, "c": 3}), 2) self.assertEqual(test.conflict1(m), 2) self.assertEqual(test.conflict4(None, [1.0, 2.0, 3.0]), 1) self.assertEqual(test.conflict4(None, 1.0), 2) self.assertEqual(test.conflict5([1.0, 2.0, 3.0]), 1) self.assertEqual(test.conflict5(1.0), 2) def testVarArgsCtor(self): va0 = self.VarArgs('1') va1 = self.VarArgs('1', 'a') va2 = self.VarArgs('1', 'a', 'b') self.assertTrue(isinstance(va0.rest, self.ObjectA)) self.assertTrue(isinstance(va1.rest, self.ObjectA)) self.assertTrue(isinstance(va2.rest, self.ObjectA)) self.assertEqual(len(va0.rest), 0) self.assertEqual(len(va1.rest), 1) self.assertEqual(len(va2.rest), 2) def testVarArgsMethod(self): va = self.VarArgs() a0 = va.method('a') a1 = va.method('a', 'b') a2 = va.method('a', 'b', 'c') def testVarArgsStatic(self): a0 = self.VarArgs.call() a1 = self.VarArgs.call(self.Object()) a2 = self.VarArgs.call(self.Object(), self.Object()) self.assertTrue(isinstance(a0, self.ObjectA)) self.assertEqual(len(a0), 0) self.assertTrue(isinstance(a1, self.ObjectA)) self.assertEqual(len(a1), 1) self.assertTrue(isinstance(a2, self.ObjectA)) self.assertEqual(len(a2), 2) s2 = self.VarArgs.call('a', 'b') i2 = self.VarArgs.call(1, 2) m2 = self.VarArgs.call('a', 1, 1.0) self.assertTrue(isinstance(s2, self.ObjectA)) self.assertEqual(len(s2), 2) self.assertTrue(isinstance(i2, self.ObjectA)) self.assertEqual(len(i2), 2) self.assertTrue(isinstance(m2, self.ObjectA)) self.assertEqual(len(m2), 3) def testVarArgsOverload(self): m0 = self.VarArgs.callOverload(self.Integer(1)) m1 = self.VarArgs.callOverload('a') m2 = self.VarArgs.callOverload('a', '1') self.assertTrue(isinstance(m0, self.Integer)) self.assertTrue(isinstance(m1, self.StringA)) self.assertTrue(isinstance(m2, self.StringA)) def testVarArgsStringTest(self): strArray = jpype.JArray(jpype.JString) self.assertTrue(compareList( self.VarArgs.callString('a', 'b'), ['a', 'b'])) self.assertTrue(compareList(self.VarArgs.callString('a'), ['a'])) self.assertTrue(compareList(self.VarArgs.callString(), [])) def testVarArgsPlus0(self): self.assertEqual(self.VarArgs.callString0("a"), 0) self.assertEqual(self.VarArgs.callString0("a", "b"), 1) self.assertEqual(self.VarArgs.callString0("a", "b", "c"), 2) def testVarArgsPlus1(self): var = self.VarArgs() self.assertEqual(var.callString1("a"), 0) self.assertEqual(var.callString1("a", "b"), 1) self.assertEqual(var.callString1("a", "b", "c"), 2) jpype-1.3.0/test/jpypetest/test_virtual.py000066400000000000000000000257751405671516700210030ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import jpype import common class VirtualsTestCase(common.JPypeTestCase): """ Test that we get the right method regardless of how we call it. Okay JNI determines the call type based on the return type, thus to make sure we are hitting every possible path we have to hit every possible return, in every way it can be called. """ def setUp(self): common.JPypeTestCase.setUp(self) self.vt = jpype.JClass('jpype.types.VirtualTest') def testCallBooleanImplements(self): v1 = self.vt.getBooleanImplements() self.assertEqual(v1.get(), True) self.assertEqual(self.vt.BooleanSupplier.get(v1), True) self.assertEqual(self.vt.ClassBooleanSupplier.get(v1), True) def testCallBooleanExtends(self): v1 = self.vt.getBooleanExtends() self.assertEqual(v1.get(), False) self.assertEqual(self.vt.BooleanSupplier.get(v1), False) self.assertEqual(self.vt.ClassBooleanSupplier.get(v1), True) def testCallBooleanAnon(self): v1 = self.vt.getBooleanAnon() self.assertEqual(v1.get(), False) self.assertEqual(self.vt.BooleanSupplier.get(v1), False) with self.assertRaises(TypeError): self.assertEqual(self.vt.ClassBooleanSupplier.get(v1), True) def testCallBooleanAnonExtends(self): v1 = self.vt.getBooleanAnonExtends() self.assertEqual(v1.get(), False) self.assertEqual(self.vt.BooleanSupplier.get(v1), False) self.assertEqual(self.vt.ClassBooleanSupplier.get(v1), True) def testCallCharImplements(self): v1 = self.vt.getCharImplements() self.assertEqual(v1.get(), '1') self.assertEqual(self.vt.CharSupplier.get(v1), '1') self.assertEqual(self.vt.ClassCharSupplier.get(v1), '1') def testCallCharExtends(self): v1 = self.vt.getCharExtends() self.assertEqual(v1.get(), '2') self.assertEqual(self.vt.CharSupplier.get(v1), '2') self.assertEqual(self.vt.ClassCharSupplier.get(v1), '1') def testCallCharAnon(self): v1 = self.vt.getCharAnon() self.assertEqual(v1.get(), '3') self.assertEqual(self.vt.CharSupplier.get(v1), '3') with self.assertRaises(TypeError): self.assertEqual(self.vt.ClassCharSupplier.get(v1), '1') def testCallByteImplements(self): v1 = self.vt.getByteImplements() self.assertEqual(v1.get(), 1) self.assertEqual(self.vt.ByteSupplier.get(v1), 1) self.assertEqual(self.vt.ClassByteSupplier.get(v1), 1) def testCallByteExtends(self): v1 = self.vt.getByteExtends() self.assertEqual(v1.get(), 2) self.assertEqual(self.vt.ByteSupplier.get(v1), 2) self.assertEqual(self.vt.ClassByteSupplier.get(v1), 1) def testCallByteAnon(self): v1 = self.vt.getByteAnon() self.assertEqual(v1.get(), 3) self.assertEqual(self.vt.ByteSupplier.get(v1), 3) with self.assertRaises(TypeError): self.assertEqual(self.vt.ClassByteSupplier.get(v1), 1) def testCallByteAnonExtends(self): v1 = self.vt.getByteAnonExtends() self.assertEqual(v1.get(), 4) self.assertEqual(self.vt.ByteSupplier.get(v1), 4) self.assertEqual(self.vt.ClassByteSupplier.get(v1), 1) def testCallCharAnonExtends(self): v1 = self.vt.getCharAnonExtends() self.assertEqual(v1.get(), '4') self.assertEqual(self.vt.CharSupplier.get(v1), '4') self.assertEqual(self.vt.ClassCharSupplier.get(v1), '1') def testCallShortImplements(self): v1 = self.vt.getShortImplements() self.assertEqual(v1.get(), 1) self.assertEqual(self.vt.ShortSupplier.get(v1), 1) self.assertEqual(self.vt.ClassShortSupplier.get(v1), 1) def testCallShortExtends(self): v1 = self.vt.getShortExtends() self.assertEqual(v1.get(), 2) self.assertEqual(self.vt.ShortSupplier.get(v1), 2) self.assertEqual(self.vt.ClassShortSupplier.get(v1), 1) def testCallShortAnon(self): v1 = self.vt.getShortAnon() self.assertEqual(v1.get(), 3) self.assertEqual(self.vt.ShortSupplier.get(v1), 3) with self.assertRaises(TypeError): self.assertEqual(self.vt.ClassShortSupplier.get(v1), 1) def testCallShortAnonExtends(self): v1 = self.vt.getShortAnonExtends() self.assertEqual(v1.get(), 4) self.assertEqual(self.vt.ShortSupplier.get(v1), 4) self.assertEqual(self.vt.ClassShortSupplier.get(v1), 1) def testCallIntegerImplements(self): v1 = self.vt.getIntegerImplements() self.assertEqual(v1.get(), 1) self.assertEqual(self.vt.IntegerSupplier.get(v1), 1) self.assertEqual(self.vt.ClassIntegerSupplier.get(v1), 1) def testCallIntegerExtends(self): v1 = self.vt.getIntegerExtends() self.assertEqual(v1.get(), 2) self.assertEqual(self.vt.IntegerSupplier.get(v1), 2) self.assertEqual(self.vt.ClassIntegerSupplier.get(v1), 1) def testCallIntegerAnon(self): v1 = self.vt.getIntegerAnon() self.assertEqual(v1.get(), 3) self.assertEqual(self.vt.IntegerSupplier.get(v1), 3) with self.assertRaises(TypeError): self.assertEqual(self.vt.ClassIntegerSupplier.get(v1), 1) def testCallIntegerAnonExtends(self): v1 = self.vt.getIntegerAnonExtends() self.assertEqual(v1.get(), 4) self.assertEqual(self.vt.IntegerSupplier.get(v1), 4) self.assertEqual(self.vt.ClassIntegerSupplier.get(v1), 1) def testCallLongImplements(self): v1 = self.vt.getLongImplements() self.assertEqual(v1.get(), 1) self.assertEqual(self.vt.LongSupplier.get(v1), 1) self.assertEqual(self.vt.ClassLongSupplier.get(v1), 1) def testCallLongExtends(self): v1 = self.vt.getLongExtends() self.assertEqual(v1.get(), 2) self.assertEqual(self.vt.LongSupplier.get(v1), 2) self.assertEqual(self.vt.ClassLongSupplier.get(v1), 1) def testCallLongAnon(self): v1 = self.vt.getLongAnon() self.assertEqual(v1.get(), 3) self.assertEqual(self.vt.LongSupplier.get(v1), 3) with self.assertRaises(TypeError): self.assertEqual(self.vt.ClassLongSupplier.get(v1), 1) def testCallLongAnonExtends(self): v1 = self.vt.getLongAnonExtends() self.assertEqual(v1.get(), 4) self.assertEqual(self.vt.LongSupplier.get(v1), 4) self.assertEqual(self.vt.ClassLongSupplier.get(v1), 1) def testCallFloatImplements(self): v1 = self.vt.getFloatImplements() self.assertEqual(v1.get(), 1) self.assertEqual(self.vt.FloatSupplier.get(v1), 1) self.assertEqual(self.vt.ClassFloatSupplier.get(v1), 1) def testCallFloatExtends(self): v1 = self.vt.getFloatExtends() self.assertEqual(v1.get(), 2) self.assertEqual(self.vt.FloatSupplier.get(v1), 2) self.assertEqual(self.vt.ClassFloatSupplier.get(v1), 1) def testCallFloatAnon(self): v1 = self.vt.getFloatAnon() self.assertEqual(v1.get(), 3) self.assertEqual(self.vt.FloatSupplier.get(v1), 3) with self.assertRaises(TypeError): self.assertEqual(self.vt.ClassFloatSupplier.get(v1), 1) def testCallFloatAnonExtends(self): v1 = self.vt.getFloatAnonExtends() self.assertEqual(v1.get(), 4) self.assertEqual(self.vt.FloatSupplier.get(v1), 4) self.assertEqual(self.vt.ClassFloatSupplier.get(v1), 1) def testCallDoubleImplements(self): v1 = self.vt.getDoubleImplements() self.assertEqual(v1.get(), 1) self.assertEqual(self.vt.DoubleSupplier.get(v1), 1) self.assertEqual(self.vt.ClassDoubleSupplier.get(v1), 1) def testCallDoubleExtends(self): v1 = self.vt.getDoubleExtends() self.assertEqual(v1.get(), 2) self.assertEqual(self.vt.DoubleSupplier.get(v1), 2) self.assertEqual(self.vt.ClassDoubleSupplier.get(v1), 1) def testCallDoubleAnon(self): v1 = self.vt.getDoubleAnon() self.assertEqual(v1.get(), 3) self.assertEqual(self.vt.DoubleSupplier.get(v1), 3) with self.assertRaises(TypeError): self.assertEqual(self.vt.ClassDoubleSupplier.get(v1), 1) def testCallDoubleAnonExtends(self): v1 = self.vt.getDoubleAnonExtends() self.assertEqual(v1.get(), 4) self.assertEqual(self.vt.DoubleSupplier.get(v1), 4) self.assertEqual(self.vt.ClassDoubleSupplier.get(v1), 1) def testCallObjectImplements(self): v1 = self.vt.getObjectImplements() self.assertEqual(v1.get(), 'implements') self.assertEqual(self.vt.ObjectSupplier.get(v1), "implements") self.assertEqual(self.vt.ClassObjectSupplier.get(v1), "implements") def testCallObjectExtends(self): v1 = self.vt.getObjectExtends() self.assertEqual(v1.get(), 'extends') self.assertEqual(self.vt.ObjectSupplier.get(v1), "extends") self.assertEqual(self.vt.ClassObjectSupplier.get(v1), "implements") def testCallObjectAnon(self): v1 = self.vt.getObjectAnon() self.assertEqual(v1.get(), 'anon') self.assertEqual(self.vt.ObjectSupplier.get(v1), "anon") with self.assertRaises(TypeError): self.assertEqual(self.vt.ClassObjectSupplier.get(v1), "implements") def testCallObjectAnonExtends(self): v1 = self.vt.getObjectAnonExtends() self.assertEqual(v1.get(), 'anon-override') self.assertEqual(self.vt.ObjectSupplier.get(v1), "anon-override") self.assertEqual(self.vt.ClassObjectSupplier.get(v1), "implements") # Success is not segfaulting def testCallVoidImplements(self): v1 = self.vt.getVoidImplements() v1.get() self.vt.VoidSupplier.get(v1) self.vt.ClassVoidSupplier.get(v1) def testCallVoidExtends(self): v1 = self.vt.getVoidExtends() v1.get() self.vt.VoidSupplier.get(v1) self.vt.ClassVoidSupplier.get(v1) def testCallVoidAnon(self): v1 = self.vt.getVoidAnon() v1.get() self.vt.VoidSupplier.get(v1) with self.assertRaises(TypeError): self.vt.ClassVoidSupplier.get(v1) def testCallVoidAnonExtends(self): v1 = self.vt.getVoidAnonExtends() v1.get() self.vt.VoidSupplier.get(v1) self.vt.ClassVoidSupplier.get(v1) jpype-1.3.0/test/jpypetest/test_zzz.py000066400000000000000000000025361405671516700201400ustar00rootroot00000000000000# ***************************************************************************** # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See NOTICE file for details. # # ***************************************************************************** import sys import _jpype import jpype from jpype.types import * from jpype import JPackage, java import common import pytest try: import numpy as np except ImportError: pass class ZZZTestCase(common.JPypeTestCase): def setUp(self): common.JPypeTestCase.setUp(self) def testShutdown(self): # Install a coverage hook instance = JClass("org.jpype.JPypeContext").getInstance() JClass("jpype.common.OnShutdown").addCoverageHook(instance) # Shutdown jpype.shutdownJVM() # Check that shutdown does not raise jpype._core._JTerminate()