diff --git a/.asf.yaml b/.asf.yaml
new file mode 100644
index 00000000000..d3643eda344
--- /dev/null
+++ b/.asf.yaml
@@ -0,0 +1,30 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+github:
+ description: "Apache Commons Lang"
+ homepage: https://commons.apache.org/lang/
+
+notifications:
+ commits: commits@commons.apache.org
+ issues: issues@commons.apache.org
+ pullrequests: issues@commons.apache.org
+ jira_options: link label
+ jobs: notifications@commons.apache.org
+ # commits_bot_dependabot: dependabot@commons.apache.org
+ issues_bot_dependabot: dependabot@commons.apache.org
+ pullrequests_bot_dependabot: dependabot@commons.apache.org
+ issues_bot_codecov-commenter: notifications@commons.apache.org
+ pullrequests_bot_codecov-commenter: notifications@commons.apache.org
diff --git a/.gitattributes b/.gitattributes
index a3546495c96..715c926ab11 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -5,7 +5,7 @@
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/.travis.yml b/.github/GH-ROBOTS.txt
similarity index 67%
rename from .travis.yml
rename to .github/GH-ROBOTS.txt
index f80bbe83319..64a88674fe4 100644
--- a/.travis.yml
+++ b/.github/GH-ROBOTS.txt
@@ -5,7 +5,7 @@
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -13,22 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-language: java
-jdk:
- - openjdk8
- - openjdk11
- - openjdk13
- - openjdk-ea
-
-matrix:
- include:
- - os: linux-ppc64le
- jdk: openjdk8
- allow_failures:
- - jdk: openjdk-ea
-
-script:
- - mvn
-
-after_success:
- - mvn clean test jacoco:report coveralls:report -Ptravis-jacoco javadoc:javadoc -Ddoclint=all
+# Keeps on creating FUD PRs in test code
+# Does not follow Apache disclosure policies
+User-agent: JLLeitschuh/security-research
+Disallow: *
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 00000000000..08d5e7de792
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,26 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+version: 2
+updates:
+ - package-ecosystem: "maven"
+ directory: "/"
+ schedule:
+ interval: "quarterly"
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "quarterly"
+
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 00000000000..9ff35c83e79
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,30 @@
+
+
+Thanks for your contribution to [Apache Commons](https://commons.apache.org/)! Your help is appreciated!
+
+Before you push a pull request, review this list:
+
+- [ ] Read the [contribution guidelines](CONTRIBUTING.md) for this project.
+- [ ] Read the [ASF Generative Tooling Guidance](https://www.apache.org/legal/generative-tooling.html) if you use Artificial Intelligence (AI).
+- [ ] I used AI to create any part of, or all of, this pull request. Which AI tool was used to create this pull request, and to what extent did it contribute?
+- [ ] Run a successful build using the default [Maven](https://maven.apache.org/) goal with `mvn`; that's `mvn` on the command line by itself.
+- [ ] Write unit tests that match behavioral changes, where the tests fail if the changes to the runtime are not applied. This may not always be possible, but it is a best practice.
+- [ ] Write a pull request description that is detailed enough to understand what the pull request does, how, and why.
+- [ ] Each commit in the pull request should have a meaningful subject line and body. Note that a maintainer may squash commits during the merge process.
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
new file mode 100644
index 00000000000..507f66d904f
--- /dev/null
+++ b/.github/workflows/codeql-analysis.yml
@@ -0,0 +1,86 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+name: "CodeQL"
+
+on:
+ push:
+ branches: [ master ]
+ pull_request:
+ # The branches below must be a subset of the branches above
+ branches: [ master ]
+ schedule:
+ - cron: '33 9 * * 4'
+
+permissions:
+ contents: read
+
+jobs:
+ analyze:
+ name: Analyze
+ runs-on: ubuntu-latest
+ permissions:
+ actions: read
+ contents: read
+ security-events: write
+
+ strategy:
+ max-parallel: 20
+ fail-fast: false
+ matrix:
+ language: [ 'java', 'javascript' ]
+ # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
+ # Learn more about CodeQL language support at https://git.io/codeql-language-support
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+ with:
+ persist-credentials: false
+ - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 #v6.1.0
+ with:
+ path: ~/.m2/repository
+ key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+ restore-keys: |
+ ${{ runner.os }}-maven-
+
+ # Initializes the CodeQL tools for scanning.
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9
+ with:
+ languages: ${{ matrix.language }}
+ # If you wish to specify custom queries, you can do so here or in a config file.
+ # By default, queries listed here will override any specified in a config file.
+ # Prefix the list here with "+" to use these queries and those in the config file.
+ # queries: ./path/to/local/query, your-org/your-repo/queries@main
+
+ # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
+ # If this step fails, then you should remove it and run the build manually (see below)
+ - name: Autobuild
+ uses: github/codeql-action/autobuild@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9
+
+ # âšī¸ Command-line programs to run using the OS shell.
+ # đ https://git.io/JvXDl
+
+ # âī¸ If the Autobuild fails above, remove it and uncomment the following three lines
+ # and modify them (or add more) to build your code if your project
+ # uses a compiled language
+
+ #- run: |
+ # make bootstrap
+ # make release
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9
diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml
new file mode 100644
index 00000000000..4c17443c92b
--- /dev/null
+++ b/.github/workflows/dependency-review.yml
@@ -0,0 +1,31 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+name: 'Dependency Review'
+on: [pull_request]
+
+permissions:
+ contents: read
+
+jobs:
+ dependency-review:
+ runs-on: ubuntu-latest
+ steps:
+ - name: 'Checkout Repository'
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+ - name: 'Dependency Review PR'
+ uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0
diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
index 757411826ef..a6641b1dfc4 100644
--- a/.github/workflows/maven.yml
+++ b/.github/workflows/maven.yml
@@ -5,7 +5,7 @@
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -15,21 +15,48 @@
name: Java CI
-on: [push]
+on:
+ push:
+ branches:
+ - 'master'
+ pull_request: {}
+
+permissions:
+ contents: read
jobs:
build:
- runs-on: ubuntu-latest
+ runs-on: ${{ matrix.os }}
+ continue-on-error: ${{ matrix.experimental }}
strategy:
+ max-parallel: 20
matrix:
- java: [ '1.8', '11.0.4', '12.0.2' ]
-
+ os: [ubuntu-latest, windows-latest, macos-latest]
+ java: [ 8, 11, 17, 21, 25, 26 ]
+ experimental: [false]
+ include:
+ - java: 27-ea
+ experimental: true
+ os: ubuntu-latest
+ - java: 28-ea
+ experimental: true
+ os: ubuntu-latest
+
steps:
- - uses: actions/checkout@v1
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+ with:
+ persist-credentials: false
+ - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 #v6.1.0
+ with:
+ path: ~/.m2/repository
+ key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+ restore-keys: |
+ ${{ runner.os }}-maven-
- name: Set up JDK ${{ matrix.java }}
- uses: actions/setup-java@v1
+ uses: actions/setup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c # 6.0.0
with:
+ distribution: ${{ runner.os == 'macOS' && matrix.java == '8' && 'zulu' || 'temurin' }}
java-version: ${{ matrix.java }}
- name: Build with Maven
- run: mvn -V apache-rat:check spotbugs:check javadoc:javadoc -Ddoclint=all package --file pom.xml
+ run: mvn --errors --show-version --batch-mode --no-transfer-progress -Ddoclint=all
diff --git a/.github/workflows/scorecards-analysis.yml b/.github/workflows/scorecards-analysis.yml
new file mode 100644
index 00000000000..c9b01ffcf8c
--- /dev/null
+++ b/.github/workflows/scorecards-analysis.yml
@@ -0,0 +1,69 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache license, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the license for the specific language governing permissions and
+# limitations under the license.
+
+name: "Scorecards supply-chain security"
+
+on:
+ branch_protection_rule:
+ schedule:
+ - cron: "30 1 * * 6" # Weekly on Saturdays
+ push:
+ branches: [ "master" ]
+
+permissions: read-all
+
+jobs:
+
+ analysis:
+
+ name: "Scorecards analysis"
+ runs-on: ubuntu-latest
+ permissions:
+ # Needed to upload the results to the code-scanning dashboard.
+ security-events: write
+ actions: read
+ id-token: write # This is required for requesting the JWT
+ contents: read # This is required for actions/checkout
+
+ steps:
+
+ - name: "Checkout code"
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+ with:
+ persist-credentials: false
+
+ - name: "Run analysis"
+ uses: ossf/scorecard-action@2d1146689b8cda280b9bc96326124645441f03bc #2.4.4
+ with:
+ results_file: results.sarif
+ results_format: sarif
+ # A read-only PAT token, which is sufficient for the action to function.
+ # The relevant discussion: https://github.com/ossf/scorecard-action/issues/188
+ repo_token: ${{ secrets.GITHUB_TOKEN }}
+ # Publish the results for public repositories to enable scorecard badges.
+ # For more details: https://github.com/ossf/scorecard-action#publishing-results
+ publish_results: true
+
+ - name: "Upload artifact"
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
+ with:
+ name: SARIF file
+ path: results.sarif
+ retention-days: 5
+
+ - name: "Upload to code-scanning"
+ uses: github/codeql-action/upload-sarif@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9
+ with:
+ sarif_file: results.sarif
diff --git a/.gitignore b/.gitignore
index c30f980e360..8d85ed51cf3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@ maven-eclipse.xml
build.properties
site-content
*~
+.mvn/
# IntelliJ IDEA files
.idea
@@ -18,3 +19,11 @@ site-content
.project
.externalToolBuilders
.checkstyle
+
+# jenv's version file
+.java-version
+/.DS_Store
+
+# NetBeans files
+nb-configuration.xml
+nbactions.xml
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 00000000000..b4342f33ca5
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,17 @@
+
+The Apache code of conduct page is [https://www.apache.org/foundation/policies/conduct.html](https://www.apache.org/foundation/policies/conduct.html).
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index cf6b5657134..88b72207b87 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -6,7 +6,7 @@
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
+ https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
@@ -25,7 +25,7 @@
| commons-build-plugin/trunk/src/main/resources/commons-xdoc-templates |
+======================================================================+
| |
- | 1) Re-generate using: mvn commons:contributing-md |
+ | 1) Re-generate using: mvn commons-build:contributing-md |
| |
| 2) Set the following properties in the component's pom: |
| - commons.jira.id (required, alphabetic, upper case) |
@@ -41,38 +41,40 @@
Contributing to Apache Commons Lang
======================
-You have found a bug or you have an idea for a cool new feature? Contributing code is a great way to give something back to
-the open source community. Before you dig right into the code there are a few guidelines that we need contributors to
-follow so that we can have a chance of keeping on top of things.
+Have you found a bug or have an idea for a cool new feature? Contributing code is a great way to give something back to the open-source community.
+Before you dig right into the code, we need contributors to follow a few guidelines to have a chance of keeping on top of things.
Getting Started
---------------
+ Make sure you have a [JIRA account](https://issues.apache.org/jira/).
-+ Make sure you have a [GitHub account](https://github.com/signup/free).
++ Make sure you have a [GitHub account](https://github.com/signup). This is not essential, but makes providing patches much easier.
+ If you're planning to implement a new feature it makes sense to discuss your changes on the [dev list](https://commons.apache.org/mail-lists.html) first. This way you can make sure you're not wasting your time on something that isn't considered to be in Apache Commons Lang's scope.
+ Submit a [Jira Ticket][jira] for your issue, assuming one does not already exist.
+ Clearly describe the issue including steps to reproduce when it is a bug.
+ Make sure you fill in the earliest version that you know has the issue.
+ Find the corresponding [repository on GitHub](https://github.com/apache/?query=commons-),
-[fork](https://help.github.com/articles/fork-a-repo/) and check out your forked repository.
+[fork](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo) and check out your forked repository. If you don't have a GitHub account, you can still clone the Commons repository.
Making Changes
--------------
+ Create a _topic branch_ for your isolated work.
- * Usually you should base your branch on the `master` or `trunk` branch.
- * A good topic branch name can be the JIRA bug id plus a keyword, e.g. `LANG-123-InputStream`.
+ * Usually you should base your branch from the `master` branch.
+ * A good topic branch name can be the JIRA bug ID plus a keyword, e.g. `LANG-123-InputStream`.
* If you have submitted multiple JIRA issues, try to maintain separate branches and pull requests.
+ Make commits of logical units.
* Make sure your commit messages are meaningful and in the proper format. Your commit message should contain the key of the JIRA issue.
- * e.g. `LANG-123: Close input stream earlier`
+ * For example, `[LANG-123] Close input stream sooner`
+ Respect the original code style:
- + Only use spaces for indentation.
+ + Only use spaces for indentation; you can check for unnecessary whitespace with `git diff` before committing.
+ Create minimal diffs - disable _On Save_ actions like _Reformat Source Code_ or _Organize Imports_. If you feel the source code should be reformatted create a separate PR for this change first.
- + Check for unnecessary whitespace with `git diff` -- check before committing.
-+ Make sure you have added the necessary tests for your changes, typically in `src/test/java`.
-+ Run all the tests with `mvn clean verify` to assure nothing else was accidentally broken.
++ Write unit tests that match behavioral changes, where the tests fail if the changes to the runtime are not applied. This may not always be possible but is a best practice.
+Unit tests are typically in the `src/test/java` directory.
++ Run a successful build using the default [Maven](https://maven.apache.org/) goal with `mvn`; that's `mvn` on the command line by itself.
++ Write a pull request description that is detailed enough to understand what the pull request does, how, and why.
++ Each commit in the pull request should have a meaningful subject line and body. Note that commits might be squashed by a maintainer on merge.
+
Making Trivial Changes
----------------------
@@ -80,7 +82,7 @@ Making Trivial Changes
The JIRA tickets are used to generate the changelog for the next release.
For changes of a trivial nature to comments and documentation, it is not always necessary to create a new ticket in JIRA.
-In this case, it is appropriate to start the first line of a commit with '(doc)' instead of a ticket number.
+In this case, it is appropriate to start the first line of a commit with '[doc]' or '[javadoc]' instead of a ticket number.
Submitting Changes
@@ -106,10 +108,9 @@ Additional Resources
+ [Contributing patches](https://commons.apache.org/patches.html)
+ [Apache Commons Lang JIRA project page][jira]
+ [Contributor License Agreement][cla]
-+ [General GitHub documentation](https://help.github.com/)
-+ [GitHub pull request documentation](https://help.github.com/articles/creating-a-pull-request/)
++ [General GitHub documentation](https://docs.github.com/)
++ [GitHub pull request documentation](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request)
+ [Apache Commons Twitter Account](https://twitter.com/ApacheCommons)
-+ `#apache-commons` IRC channel on `irc.freenode.net`
[cla]:https://www.apache.org/licenses/#clas
[jira]:https://issues.apache.org/jira/browse/LANG
diff --git a/Jenkinsfile b/Jenkinsfile
deleted file mode 100644
index 36799d0f5ff..00000000000
--- a/Jenkinsfile
+++ /dev/null
@@ -1,115 +0,0 @@
-#!groovy
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-pipeline {
- agent {
- node {
- label 'ubuntu'
- }
- }
-
- tools {
- maven 'Maven 3 (latest)'
- jdk 'JDK 1.8 (latest)'
- }
-
- stages {
- stage('Build') {
- steps {
- sh 'mvn'
- }
- post {
- always {
- junit(testResults: '**/surefire-reports/*.xml', allowEmptyResults: true)
- }
- }
- }
- stage('Deploy') {
- when {
- branch 'master'
- }
- steps {
- sh 'mvn deploy'
- }
- }
- }
-
- // Send out notifications on unsuccessful builds.
- post {
- // If this build failed, send an email to the list.
- failure {
- script {
- if(env.BRANCH_NAME == "master") {
- def state = (currentBuild.previousBuild != null) && (currentBuild.previousBuild.result == 'FAILURE') ? "Still failing" : "Failure"
- emailext(
- subject: "[Lang] Change on branch \"${env.BRANCH_NAME}\": ${env.JOB_NAME} - Build # ${env.BUILD_NUMBER} - $state",
- body: """The Apache Jenkins build system has built ${env.JOB_NAME} (build #${env.BUILD_NUMBER})
-
-Status: ${currentBuild.result}
-
-Check console output at ${env.BUILD_URL} to view the results.
-""",
- to: "notifications@commons.apache.org",
- recipientProviders: [[$class: 'DevelopersRecipientProvider']]
- )
- }
- }
- }
-
- // If this build didn't fail, but there were failing tests, send an email to the list.
- unstable {
- script {
- if(env.BRANCH_NAME == "master") {
- def state = (currentBuild.previousBuild != null) && (currentBuild.previousBuild.result == 'UNSTABLE') ? "Still unstable" : "Unstable"
- emailext(
- subject: "[Lang] Change on branch \"${env.BRANCH_NAME}\": ${env.JOB_NAME} - Build # ${env.BUILD_NUMBER} - $state",
- body: """The Apache Jenkins build system has built ${env.JOB_NAME} (build #${env.BUILD_NUMBER})
-
-Status: ${currentBuild.result}
-
-Check console output at ${env.BUILD_URL} to view the results.
-""",
- to: "notifications@commons.apache.org",
- recipientProviders: [[$class: 'DevelopersRecipientProvider']]
- )
- }
- }
- }
-
- // Send an email, if the last build was not successful and this one is.
- success {
- script {
- if ((env.BRANCH_NAME == "master") && (currentBuild.previousBuild != null) && (currentBuild.previousBuild.result != 'SUCCESS')) {
- emailext (
- subject: "[Lang] Change on branch \"${env.BRANCH_NAME}\": ${env.JOB_NAME} - Build # ${env.BUILD_NUMBER} - Back to normal",
- body: """The Apache Jenkins build system has built ${env.JOB_NAME} (build #${env.BUILD_NUMBER})
-
-Status: ${currentBuild.result}
-
-Check console output at ${env.BUILD_URL} to view the results.
-""",
- to: "notifications@commons.apache.org",
- recipientProviders: [[$class: 'DevelopersRecipientProvider']]
- )
- }
- }
- }
- }
-}
diff --git a/LICENSE.txt b/LICENSE.txt
index d6456956733..ff9ad4530f5 100644
--- a/LICENSE.txt
+++ b/LICENSE.txt
@@ -193,7 +193,7 @@
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
+ https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/NOTICE.txt b/NOTICE.txt
index 13a31408974..246f39cc1d1 100644
--- a/NOTICE.txt
+++ b/NOTICE.txt
@@ -1,5 +1,5 @@
Apache Commons Lang
-Copyright 2001-2019 The Apache Software Foundation
+Copyright 2001-2026 The Apache Software Foundation
This product includes software developed at
-The Apache Software Foundation (http://www.apache.org/).
+The Apache Software Foundation (https://www.apache.org/).
diff --git a/README.md b/README.md
index ae9cdc2041c..116f814b13d 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
+ https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
@@ -25,7 +25,7 @@
| commons-build-plugin/trunk/src/main/resources/commons-xdoc-templates |
+======================================================================+
| |
- | 1) Re-generate using: mvn commons:readme-md |
+ | 1) Re-generate using: mvn commons-build:readme-md |
| |
| 2) Set the following properties in the component's pom: |
| - commons.componentid (required, alphabetic, lower case) |
@@ -43,65 +43,85 @@
Apache Commons Lang
===================
-[](https://travis-ci.org/apache/commons-lang)
-[](https://coveralls.io/r/apache/commons-lang)
-[](https://maven-badges.herokuapp.com/maven-central/org.apache.commons/commons-lang3/)
-[](https://javadoc.io/doc/org.apache.commons/commons-lang3/3.9)
+[](https://github.com/apache/commons-lang/actions/workflows/maven.yml)
+[](https://search.maven.org/artifact/org.apache.commons/commons-lang3)
+[](https://javadoc.io/doc/org.apache.commons/commons-lang3/3.20.0)
+[](https://github.com/apache/commons-lang/actions/workflows/codeql-analysis.yml)
+[](https://api.securityscorecards.dev/projects/github.com/apache/commons-lang)
Apache Commons Lang, a package of Java utility classes for the
classes that are in java.lang's hierarchy, or are considered to be so
standard as to justify existence in java.lang.
+ The code is tested using the latest revision of the JDK for supported
+ LTS releases: 8, 11, 17, 21 and 25 currently.
+ See https://github.com/apache/commons-lang/blob/master/.github/workflows/maven.yml
+
+ Please ensure your build environment is up-to-date and kindly report any build issues.
+
Documentation
-------------
-More information can be found on the [Apache Commons Lang homepage](https://commons.apache.org/proper/commons-lang/).
-The [Javadoc](https://commons.apache.org/proper/commons-lang/javadocs/api-release/) can be browsed.
-Questions related to the usage of Apache Commons Lang should be posted to the [user mailing list][ml].
+More information can be found on the [Apache Commons Lang homepage](https://commons.apache.org/proper/commons-lang).
+The [Javadoc](https://commons.apache.org/proper/commons-lang/apidocs) can be browsed.
+Questions related to the usage of Apache Commons Lang should be posted to the [user mailing list](https://commons.apache.org/mail-lists.html).
-Where can I get the latest release?
------------------------------------
-You can download source and binaries from our [download page](https://commons.apache.org/proper/commons-lang3/download_lang3.cgi).
+Getting the latest release
+--------------------------
+You can download source and binaries from our [download page](https://commons.apache.org/proper/commons-lang/download_lang.cgi).
-Alternatively you can pull it from the central Maven repositories:
+Alternatively, you can pull it from the central Maven repositories:
```xml
org.apache.commonscommons-lang3
- 3.9
+ 3.20.0
```
+Building
+--------
+
+Building requires a Java JDK and [Apache Maven](https://maven.apache.org/).
+The required Java version is found in the `pom.xml` as the `maven.compiler.source` property.
+
+From a command shell, run `mvn` without arguments to invoke the default Maven goal to run all tests and checks.
+
Contributing
------------
-We accept Pull Requests via GitHub. The [developer mailing list][ml] is the main channel of communication for contributors.
+We accept Pull Requests via GitHub. The [developer mailing list](https://commons.apache.org/mail-lists.html) is the main channel of communication for contributors.
There are some guidelines which will make applying PRs easier for us:
+ No tabs! Please use spaces for indentation.
-+ Respect the code style.
++ Respect the existing code style for each file.
+ Create minimal diffs - disable on save actions like reformat source code or organize imports. If you feel the source code should be reformatted create a separate PR for this change.
-+ Provide JUnit tests for your changes and make sure your changes don't break any existing tests by running ```mvn clean test```.
++ Provide JUnit tests for your changes and make sure your changes don't break any existing tests by running `mvn`.
++ Before you push a PR, run `mvn` (without arguments). This runs the default goal which contains all build checks.
++ To see the code coverage report, regardless of coverage failures, run `mvn clean site -Dcommons.jacoco.haltOnFailure=false -Pjacoco`
If you plan to contribute on a regular basis, please consider filing a [contributor license agreement](https://www.apache.org/licenses/#clas).
You can learn more about contributing via GitHub in our [contribution guidelines](CONTRIBUTING.md).
License
-------
-This code is under the [Apache Licence v2](https://www.apache.org/licenses/LICENSE-2.0).
+This code is licensed under the [Apache License v2](https://www.apache.org/licenses/LICENSE-2.0).
See the `NOTICE.txt` file for required notices and attributions.
-Donations
----------
-You like Apache Commons Lang? Then [donate back to the ASF](https://www.apache.org/foundation/contributing.html) to support the development.
+Donating
+--------
+You like Apache Commons Lang? Then [donate back to the ASF](https://www.apache.org/foundation/contributing.html) to support development.
Additional Resources
--------------------
+ [Apache Commons Homepage](https://commons.apache.org/)
+ [Apache Issue Tracker (JIRA)](https://issues.apache.org/jira/browse/LANG)
++ [Apache Commons Slack Channel](https://the-asf.slack.com/archives/C60NVB8AD)
+ [Apache Commons Twitter Account](https://twitter.com/ApacheCommons)
-+ `#apache-commons` IRC channel on `irc.freenode.org`
-[ml]:https://commons.apache.org/mail-lists.html
+Apache Commons Components
+-------------------------
+
+Please see the [list of components](https://commons.apache.org/components.html)
diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index f9ee7aa22f3..c8b809c6cca 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -1,6 +1,1374 @@
- Apache Commons Lang
- Version 3.9
- Release Notes
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License. You may obtain a copy of the License at
+
+https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Apache Commons Lang 3.20.0 Release Notes
+----------------------------------------
+
+The Apache Commons Lang team is pleased to announce the release of Apache Commons Lang 3.20.0.
+
+Commons Lang is a set of utility functions and reusable components that should be useful in any Java environment.
+
+Starting with Commons Lang 3.9, we target Java 8, using those features.
+
+For advice on upgrading from 2.x to 3.x, see:
+
+ https://commons.apache.org/lang/article3_0.html
+
+Apache Commons Lang, a package of Java utility classes for the
+classes that are in java.lang's hierarchy, or are considered to be so
+standard as to justify existence in java.lang.
+
+The code is tested using the latest revision of the JDK for supported
+LTS releases: 8, 11, 17, 21 and 25 currently.
+See https://github.com/apache/commons-lang/blob/master/.github/workflows/maven.yml
+
+Please ensure your build environment is up-to-date and kindly report any build issues.
+
+This is a feature and maintenance release. Java 8 or later is required.
+
+Changes in this version include:
+
+New features:
+o Add SystemProperties.getPath(String, Supplier). Thanks to Gary Gregory.
+o Add JavaVersion.JAVA_25. Thanks to Gary Gregory.
+o Add JavaVersion.JAVA_26. Thanks to Gary Gregory.
+o Add SystemUtils.IS_JAVA_25. Thanks to Gary Gregory.
+o Add SystemUtils.IS_JAVA_26. Thanks to Gary Gregory.
+o Add MutablePair.ofNonNull(Map.Entry). Thanks to jack5505, Gary Gregory.
+o Add TimedSemaphore.builder(), Builder, and deprecate constructors. Thanks to Gary Gregory.
+o LANG-1504: Adding labels and history to split StopWatch #1473. Thanks to Edwin Delgado H, Gary Gregory.
+
+Fixed Bugs:
+o Optimize ObjectToStringComparator.compare() method #1449. Thanks to mayuming, Gary Gregory.
+o [javadoc] Improve StringUtils Javadoc #1450. Thanks to Marcono1234, Gary Gregory.
+o Fix internal inverted logic in private isEnum() method and correct its usage in getFirstEnum() #1454. Thanks to mayuming, Gary Gregory.
+o Use accessors in ToStringStyle so subclasses can effectively override them. Thanks to William Degrange, Gary Gregory, Rob Spoor.
+o `LocaleUtils.toLocale(String)` for a 2 letter country code now returns a value instead of throwing an `IllegalArgumentException`. Thanks to jack5505, Gary Gregory.
+o Fix typo in StringUtils.trunctate() IllegalArgumentException message and test assertion messages. Thanks to mayuming, Gary Gregory.
+o Fix test fixture in ReflectionDiffBuilderTest.testTransientFieldDifference() #1464. Thanks to mayuming, Gary Gregory.
+o LANG-1789: NullPointerException when generating NoSuchMethodException in MethodUtils. Thanks to Hylke van der Schaaf, Gary Gregory.
+o LANG-1786: Map deprecated TimeZone short IDs and avoid JRE WARNINGs to the console #1483. Thanks to Daniel Migowski, Gary Gregory, Lenny Primak.
+o LANG-1792: TypeUtils.toString() skips angle brackets for Class type. Thanks to Mykhailo Hryb, Gary Gregory.
+o Mention JDK 25 LTS as a tested version in the release notes #1485. Thanks to Sebastian Peters, Gary Gregory.
+
+Changes:
+o Bump org.apache.commons:commons-parent from 88 to 92 #1472, #1484. Thanks to Gary Gregory, Dependabot.
+
+
+Historical list of changes: https://commons.apache.org/proper/commons-lang/changes.html
+
+For complete information on Apache Commons Lang, including instructions on how to submit bug reports,
+patches, or suggestions for improvement, see the Apache Commons Lang website:
+
+https://commons.apache.org/proper/commons-lang/
+
+Download page: https://commons.apache.org/proper/commons-lang/download_lang.cgi
+
+Have fun!
+Apache Commons Team
+
+-----------------------------------------------------------------------------
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License. You may obtain a copy of the License at
+
+https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Apache Commons Lang 3.20.0 Release Notes
+----------------------------------------
+
+The Apache Commons Lang team is pleased to announce the release of Apache Commons Lang 3.20.0.
+
+Commons Lang is a set of utility functions and reusable components that should be useful in any Java environment.
+
+Starting with Commons Lang 3.9, we target Java 8, using those features.
+
+For advice on upgrading from 2.x to 3.x, see:
+
+ https://commons.apache.org/lang/article3_0.html
+
+Apache Commons Lang, a package of Java utility classes for the
+classes that are in java.lang's hierarchy, or are considered to be so
+standard as to justify existence in java.lang.
+
+The code is tested using the latest revision of the JDK for supported
+LTS releases: 8, 11, 17 and 21 currently.
+See https://github.com/apache/commons-lang/blob/master/.github/workflows/maven.yml
+
+Please ensure your build environment is up-to-date and kindly report any build issues.
+
+This is a feature and maintenance release. Java 8 or later is required.
+
+Changes in this version include:
+
+New features:
+o Add SystemProperties.getPath(String, Supplier). Thanks to Gary Gregory.
+o Add JavaVersion.JAVA_25. Thanks to Gary Gregory.
+o Add JavaVersion.JAVA_26. Thanks to Gary Gregory.
+o Add SystemUtils.IS_JAVA_25. Thanks to Gary Gregory.
+o Add SystemUtils.IS_JAVA_26. Thanks to Gary Gregory.
+o Add MutablePair.ofNonNull(Map.Entry). Thanks to jack5505, Gary Gregory.
+o Add TimedSemaphore.builder(), Builder, and deprecate constructors. Thanks to Gary Gregory.
+o LANG-1504: Adding labels and history to split StopWatch #1473. Thanks to Edwin Delgado H, Gary Gregory.
+
+Fixed Bugs:
+o Optimize ObjectToStringComparator.compare() method #1449. Thanks to mayuming, Gary Gregory.
+o [javadoc] Improve StringUtils Javadoc #1450. Thanks to Marcono1234, Gary Gregory.
+o Fix internal inverted logic in private isEnum() method and correct its usage in getFirstEnum() #1454. Thanks to mayuming, Gary Gregory.
+o Use accessors in ToStringStyle so subclasses can effectively override them. Thanks to William Degrange, Gary Gregory, Rob Spoor.
+o `LocaleUtils.toLocale(String)` for a 2 letter country code now returns a value instead of throwing an `IllegalArgumentException`. Thanks to jack5505, Gary Gregory.
+o Fix typo in StringUtils.trunctate() IllegalArgumentException message and test assertion messages. Thanks to mayuming, Gary Gregory.
+o Fix test fixture in ReflectionDiffBuilderTest.testTransientFieldDifference() #1464. Thanks to mayuming, Gary Gregory.
+o LANG-1789: NullPointerException when generating NoSuchMethodException in MethodUtils. Thanks to Hylke van der Schaaf, Gary Gregory.
+o LANG-1786: Map deprecated TimeZone short IDs and avoid JRE WARNINGs to the console #1483. Thanks to Daniel Migowski, Gary Gregory, Lenny Primak.
+
+Changes:
+o Bump org.apache.commons:commons-parent from 88 to 92 #1472, #1484. Thanks to Gary Gregory, Dependabot.
+
+
+Historical list of changes: https://commons.apache.org/proper/commons-lang/changes.html
+
+For complete information on Apache Commons Lang, including instructions on how to submit bug reports,
+patches, or suggestions for improvement, see the Apache Commons Lang website:
+
+https://commons.apache.org/proper/commons-lang/
+
+Download page: https://commons.apache.org/proper/commons-lang/download_lang.cgi
+
+Have fun!
+Apache Commons Team
+
+-----------------------------------------------------------------------------
+
+Apache Commons Lang 3.19.0 Release Notes
+----------------------------------------
+
+The Apache Commons Lang team is pleased to announce the release of Apache Commons Lang 3.19.0.
+
+Commons Lang is a set of utility functions and reusable components that should be useful in any Java environment.
+
+Starting with Commons Lang 3.9, we target Java 8, using those features.
+
+For advice on upgrading from 2.x to 3.x, see:
+
+ https://commons.apache.org/lang/article3_0.html
+
+Apache Commons Lang, a package of Java utility classes for the
+classes that are in java.lang's hierarchy, or are considered to be so
+standard as to justify existence in java.lang.
+
+The code is tested using the latest revision of the JDK for supported
+LTS releases: 8, 11, 17 and 21 currently.
+See https://github.com/apache/commons-lang/blob/master/.github/workflows/maven.yml
+
+Please ensure your build environment is up-to-date and kindly report any build issues.
+
+This is a feature and maintenance release. Java 8 or later is required.
+
+Changes in this version include:
+
+New features:
+o Add ArrayUtils.SOFT_MAX_ARRAY_LENGTH. Thanks to Gary Gregory.
+o Add SystemUtils.IS_OS_NETWARE. Thanks to Gary Gregory.
+o Add MethodUtils.getAccessibleMethod(Class, Method). Thanks to Gary Gregory.
+o Add documentation to site for CVE-2025-48924 ClassUtils.getClass(...) can throw a StackOverflowError on very long inputs. Thanks to Gary Gregory.
+o Add StringUtils.indexOfAny(CharSequence, int, char...). Thanks to Gary Gregory.
+o Add ConcurrentException.ConcurrentException(String). Thanks to Gary Gregory.
+o Add DateUtils.toLocalDateTime(Date[, TimeZone]) #1385. Thanks to Finger, Gary Gregory, Piotr P. Karwasz.
+o Add DateUtils.toOffsetDateTime(Date[, TimeZone]). Thanks to Gary Gregory.
+o Add DateUtils.toZonedDateTime(Date[, TimeZone]). Thanks to Gary Gregory.
+o Add ByteConsumer. Thanks to Gary Gregory.
+o Add ByteSupplier. Thanks to Gary Gregory.
+o Add FailableByteConsumer. Thanks to Gary Gregory.
+o Add FailableByteSupplier. Thanks to Gary Gregory.
+o LANG-1784: Add Functions methods for null-safe mapping and chaining #1435. Thanks to Rich Dougherty, Gary Gregory.
+o LANG-1784: Add Failable methods for null-safe mapping and chaining #1435. Thanks to Rich Dougherty, Gary Gregory.
+o Add DoubleRange.fit(double). Thanks to Gary Gregory.
+o Add IntegerRange.fit(int). Thanks to Gary Gregory.
+o Add LongRange.fit(long). Thanks to Gary Gregory.
+o Add DurationUtils.get(String, TemporalUnit, long). Thanks to Gary Gregory.
+o Add DurationUtils.getMillis(String, long). Thanks to Gary Gregory.
+o Add DurationUtils.getSeconds(String, long). Thanks to Gary Gregory.
+o Add SystemProperties.getBoolean(Class, String, boolean). Thanks to Gary Gregory.
+o Add SystemProperties.getInt(Class, String, int). Thanks to Gary Gregory.
+o Add SystemProperties.getLong(Class, String, long). Thanks to Gary Gregory.
+
+Fixed Bugs:
+o LANG-1778: MethodUtils.getMatchingMethod() doesn't respect the hierarchy of methods #1414. Thanks to wuwu2000.
+o MethodUtils.getMethodObject(Class>, String, Class>...) now returns null instead of throwing a NullPointerException, as it does for other exception types. Thanks to Gary Gregory.
+o Reduce spurious failures in ArrayUtilsTest methods that test ArrayUtils.shuffle() methods. Thanks to Gary Gregory.
+o MethodUtils cannot find or invoke a public method on a public class implemented in its package-private superclass. Thanks to Gary Gregory.
+o AtomicSafeInitializer.get() can spin internally if the FailableSupplier given to AbstractConcurrentInitializer.AbstractBuilder.setInitializer(FailableSupplier) throws a RuntimeException. Thanks to Stanislav Fort, Gary Gregory.
+o LANG-1783: WordUtils.containsAllWords?() may throw PatternSyntaxException. Thanks to Arnout Engelen, Stanislav Fort, Gary Gregory.
+o LANG-1782: MethodUtils cannot find or invoke vararg methods without providing vararg types or values #1427. Thanks to Joe Ferner, Gary Gregory.
+o MethodUtils cannot find or invoke vararg methods of interface types. Thanks to Joe Ferner, Gary Gregory.
+o MethodUtils cannot find or invoke vararg methods when widening primitive types following the JLS 5.1.2. Widening Primitive Conversion. Thanks to Joe Ferner, Gary Gregory.
+o LANG-1597: Invocation fails because matching varargs method found but then discarded. Thanks to Richard Eckart de Castilho, Gary Gregory.
+o Don't check accessibility twice in MemberUtils.setAccessibleWorkaround(T). Thanks to Gary Gregory.
+o LANG-1774: Improve handling of ClassUtils.getShortCanonicalName() for invalid input #1437. Thanks to Zhongxin Yan, Madhur Lathi, Yudan Liu, Gary Gregory.
+o LANG-1720: Improve Javadocs for Conversion. Thanks to Sheung Chi Chan, Arthur Chan, Gary Gregory, Elliotte Rusty Harold.
+o Fix CalendarUtils.toLocalDate() Javadoc return type description #1440. Thanks to mayuming.
+o Fix the method name in Javadoc examples for CharUtils.isHex() #1444. Thanks to mayuming.
+o Deprecate NumberUtils.compare(byte, byte) in favor of Byte.compare(byte, byte). Thanks to Gary Gregory.
+o Deprecate NumberUtils.compare(int, int) in favor of Integer.compare(int, int). Thanks to Gary Gregory.
+o Deprecate NumberUtils.compare(long, long) in favor of Long.compare(long, long). Thanks to Gary Gregory.
+o Deprecate NumberUtils.compare(short, short) in favor of Short.compare(short, short). Thanks to Gary Gregory.
+o Deprecate obsolete system property constant SystemProperties.AWT_TOOLKIT. Thanks to Gary Gregory.
+o Deprecate obsolete system property constant SystemProperties.JAVA_AWT_FONTS. Thanks to Gary Gregory.
+o Deprecate obsolete system property constant SystemProperties.JAVA_AWT_GRAPHICSENV. Thanks to Gary Gregory.
+o Deprecate obsolete system property constant SystemProperties.JAVA_AWT_HEADLESS. Thanks to Gary Gregory.
+o Deprecate obsolete system property constant SystemProperties.JAVA_AWT_PRINTERJOB. Thanks to Gary Gregory.
+o Deprecate obsolete system property constant SystemProperties.JAVA_COMPILER. Thanks to Gary Gregory.
+o Deprecate obsolete system property constant SystemProperties.JAVA_ENDORSED_DIRS. Thanks to Gary Gregory.
+o Deprecate obsolete system property constant SystemProperties.JAVA_EXT_DIRS. Thanks to Gary Gregory.
+o Deprecate method for obsolete system property constant SystemProperties.getAwtToolkit() Thanks to Gary Gregory.
+o Deprecate method for obsolete system property constant SystemProperties.getJavaAwtFonts() Thanks to Gary Gregory.
+o Deprecate method for obsolete system property constant SystemProperties.getJavaAwtGraphicsenv() Thanks to Gary Gregory.
+o Deprecate method for obsolete system property constant SystemProperties.getJavaAwtHeadless() Thanks to Gary Gregory.
+o Deprecate method for obsolete system property constant SystemProperties.getJavaAwtPrinterjob() Thanks to Gary Gregory.
+o Deprecate method for obsolete system property constant SystemProperties.getJavaCompiler() Thanks to Gary Gregory.
+o Deprecate method for obsolete system property constant SystemProperties.getJavaEndorsedDirs() Thanks to Gary Gregory.
+o Deprecate method for obsolete system property constant SystemProperties.getJavaExtDirs() Thanks to Gary Gregory.
+o Deprecate method for obsolete system property constant SystemUtils.isJavaAwtHeadless() Thanks to Gary Gregory.
+o Deprecate constants for obsolete system property SystemUtils.JAVA_AWT_FONTS. Thanks to Gary Gregory.
+o Deprecate constants for obsolete system property SystemUtils.JAVA_AWT_GRAPHICSENV. Thanks to Gary Gregory.
+o Deprecate constants for obsolete system property SystemUtils.JAVA_AWT_HEADLESS. Thanks to Gary Gregory.
+o Deprecate constants for obsolete system property SystemUtils.JAVA_AWT_PRINTERJOB. Thanks to Gary Gregory.
+o Deprecate constants for obsolete system property SystemUtils.JAVA_COMPILER. Thanks to Gary Gregory.
+o Deprecate constants for obsolete system property SystemUtils.JAVA_ENDORSED_DIRS. Thanks to Gary Gregory.
+o Deprecate constants for obsolete system property SystemUtils.JAVA_EXT_DIRS. Thanks to Gary Gregory.
+o [javadoc] General improvements. Thanks to Gary Gregory.
+o [javadoc] Fix thrown exception documentation for MethodUtils.getMethodObject(Class>, String, Class>...). Thanks to Gary Gregory.
+o [javadoc] Strings::equalsAny: CI doc string should show it's insensitive #1416. Thanks to Scott Parish.
+o [javadoc] General Javadoc improvements. Thanks to Gary Gregory.
+o LANG-1780: [javadoc] Fix Strings Javadoc #1419. Thanks to tza.
+o [javadoc] Fix typo in Javadoc of Strings instances #1406. Thanks to Sebastian Steiner.
+o [javadoc] Fix Javadocs in ClassUtils #1410. Thanks to Hassan A Hashim.
+o [javadoc] Fix @deprecated link for StringUtils#startsWithAny #1424. Thanks to mfg92.
+o Replace old feather logotype with new oak logotype. Thanks to Gary Gregory.
+
+Changes:
+o [test] Bump org.apache.commons:commons-text from 1.13.1 to 1.14.0. Thanks to Gary Gregory.
+o Bump org.apache.commons:commons-parent from 85 to 88. Thanks to Gary Gregory.
+
+
+Historical list of changes: https://commons.apache.org/proper/commons-lang/changes.html
+
+For complete information on Apache Commons Lang, including instructions on how to submit bug reports,
+patches, or suggestions for improvement, see the Apache Commons Lang website:
+
+https://commons.apache.org/proper/commons-lang/
+
+Download page: https://commons.apache.org/proper/commons-lang/download_lang.cgi
+
+Have fun!
+Apache Commons Team
+
+-----------------------------------------------------------------------------
+
+Apache Commons Lang 3.18.0 Release Notes
+----------------------------------------
+
+The Apache Commons Lang team is pleased to announce the release of Apache Commons Lang 3.18.0.
+
+Commons Lang is a set of utility functions and reusable components that should be useful in any Java environment.
+
+Starting with Commons Lang 3.9, we target Java 8, using those features.
+
+For advice on upgrading from 2.x to 3.x, see:
+
+ https://commons.apache.org/lang/article3_0.html
+
+Apache Commons Lang, a package of Java utility classes for the
+classes that are in java.lang's hierarchy, or are considered to be so
+standard as to justify existence in java.lang.
+
+The code is tested using the latest revision of the JDK for supported
+LTS releases: 8, 11, 17 and 21 currently.
+See https://github.com/apache/commons-lang/blob/master/.github/workflows/maven.yml
+
+Please ensure your build environment is up-to-date and kindly report any build issues.
+
+This is a feature and maintenance release. Java 8 or later is required.
+
+Changes in this version include:
+
+New features:
+o Add Strings and refactor StringUtils. Thanks to Gary Gregory.
+o LANG-1747: Add StopWatch.run([Failable]Runnable) and get([Failable]Supplier). Thanks to Oliver B. Fischer, Gary Gregory.
+o Add JavaVersion.JAVA_23. Thanks to Gary Gregory.
+o Add JavaVersion.JAVA_24. Thanks to Gary Gregory.
+o Add SystemUtils.IS_JAVA_23. Thanks to Gary Gregory.
+o Add SystemUtils.IS_JAVA_24. Thanks to Gary Gregory.
+o Add IntegerRange.toIntStream(). Thanks to Gary Gregory.
+o Add LongRange.toLongStream(). Thanks to Gary Gregory.
+o Add IntStrams.of(int...). Thanks to Gary Gregory.
+o Add ArrayUtils.containsAny(int[], int...). Thanks to Gary Gregory.
+o Add CalendarUtils.toLocalDate() #725. Thanks to asgh, Gary Gregory.
+o Add SystemUtils.IS_OS_MAC_OSX_SEQUOIA. Thanks to Gary Gregory.
+o Add BasicThreadFactory.builder() and deprecate BasicThreadFactory.Builder(). Thanks to Gary Gregory.
+o Add BasicThreadFactory.daemon(). Thanks to Gary Gregory.
+o Add ArrayUtils.startsWith. Thanks to Gary Gregory.
+o Add Predicates. Thanks to Gary Gregory.
+o Add RegExUtils methods typed to CharSequence input and deprecate old versions typed to String. Thanks to Gary Gregory.
+o Add IterableStringTokenizer. Thanks to Gary Gregory.
+o Add FailableIntToFloatFunction. Thanks to Gary Gregory.
+o Add Validate.isTrue(boolean, Supplier). Thanks to Gary Gregory.
+o Add EnumUtils.getFirstEnum(Class, int, ToIntFunction, E). Thanks to Gary Gregory.
+o Add FailableToBooleanFunction. Thanks to Gary Gregory.
+o Add the @FunctionalInterface annotation to org.apache.commons.lang3.concurrent.Computable. Thanks to Gary Gregory.
+o Add SystemUtils.getJavaIoTmpDirPath(). Thanks to Gary Gregory.
+o Add SystemUtils.getJavaHomePath(). Thanks to Gary Gregory.
+o Add SystemUtils.getUserDirPath(). Thanks to Gary Gregory.
+o Add SystemUtils.getUserHomePath(). Thanks to Gary Gregory.
+o Add ArrayFill.fill(T[], FailableIntFunction)). Thanks to Gary Gregory.
+o Add SystemProperties.JAVA_SECURITY_DEBUG. Thanks to Gary Gregory.
+o Add SystemProperties.JAVA_SECURITY_KERBEROS_CONF. Thanks to Gary Gregory.
+o Add SystemProperties.JAVA_SECURITY_KERBEROS_KDC. Thanks to Gary Gregory.
+o Add SystemProperties.JAVA_SECURITY_KERBEROS_REAL. Thanks to Gary Gregory.
+o Add ArrayFill.fill(boolean[], boolean) #1386. Thanks to kommalapatiraviteja.
+o Add ObjectUtils.getIfNull(Object, Object) and deprecate defaultIfNull(Object, Object). Thanks to Pankraz76, Gary Gregory.
+o org.apache.commons.lang3.mutable.Mutable now extends Supplier. Thanks to Gary Gregory.
+o Add org.apache.commons.lang3.CharUtils.isHex(char). Thanks to Gary Gregory.
+o Add org.apache.commons.lang3.CharUtils.isOctal(char). Thanks to Gary Gregory.
+o Add org.apache.commons.lang3.concurrent.locks.LockingVisitors.reentrantLockVisitor(Object). Thanks to Gary Gregory.
+o Add org.apache.commons.lang3.concurrent.locks.LockingVisitors.create(Object, ReentrantLock). Thanks to Gary Gregory.
+o Add org.apache.commons.lang3.concurrent.locks.LockingVisitors.ReentrantLockVisitor. Thanks to Gary Gregory.
+o Add builders for LockingVisitors implementations. Thanks to Gary Gregory.
+o Add EnumSet.stream(Class). Thanks to Gary Gregory.
+o Add org.apache.commons.lang3.SystemProperties.isPropertySet(String). Thanks to Gary Gregory.
+
+Fixed Bugs:
+o Fix flaky FileUtilsWaitForTest.testWaitForNegativeDuration(). Thanks to Gary Gregory.
+o Pick up exec-maven-plugin version from parent POM. Thanks to Gary Gregory.
+o Speed up and sanitize StopWatchTest. Thanks to Gary Gregory.
+o Fix handling of non-ASCII letters and numbers in RandomStringUtils #1273. Thanks to Fabrice Benhamouda.
+o Rewrite ClassUtils.getClass(...) without recursion to avoid StackOverflowError on very long inputs.
+ OSS-Fuzz Issue 42522972: apache-commons-text:StringSubstitutorInterpolatorFuzzer: Security exception in org.apache.commons.lang3.ClassUtils.getClass. Thanks to OSS-Fuzz, Gary Gregory.
+o Remove trailing whitespace in StopWatch exception messages. Thanks to Gary Gregory.
+o LANG-1754: Use getAllSuperclassesAndInterfaces() in getMatchingMethod() #1289. Thanks to vhbcm.
+o Add details to the ArrayFill Javadoc. Thanks to Gary Gregory.
+o Add details to the ArraySorter Javadoc. Thanks to Gary Gregory.
+o Fix broken URL to project location in Maven Central #1296. Thanks to Capt. Cutlass.
+o LANG-1753: StringUtils.replaceEachRepeatedly regression in 3.11+ #1297. Thanks to Capt. Cutlass.
+o Use simplified JUnit assertion methods #1298. Thanks to Capt. Cutlass.
+o LANG-1682: Javadoc and test: Use Strings.CI.startsWithAny method instead #1299. Thanks to Capt. Cutlass.
+o Fix NullPointerException in FastDateParser.TimeZoneStrategy.setCalendar(FastDateParser, Calendar, String) on Java 23. Thanks to Gary Gregory.
+o LANG-1757: Fix NullPointerException in MethodUtils.getMatchingAccessibleMethod((Class, String, Class...)). Thanks to Gary Gregory.
+o LANG-1698: Fix StackOverflowError in TypeUtils.typeVariableToString(TypeVariable), TypeUtils.toString(Type) on Java 17 and up. Thanks to Jan Arne Sparka, Gary Gregory.
+o LANG-1511: SystemUtils is missing important documentation. Thanks to david cogen, Gary Gregory, Bruno P. Kinoshita.
+o Make Failable.run(FailableRunnable) null-safe. Thanks to Gary Gregory.
+o Make Failable.accept(*) null-safe. Thanks to Gary Gregory.
+o Improve container detection by mimicking systemd #1323. Thanks to maxxedev, Piotr P. Karwasz, Gary Gregory.
+o Make LangCollectors.collect(...) null-safe. Thanks to Gary Gregory.
+o Make LangCollectors.collect(...) null-safe. Thanks to Gary Gregory.
+o Fix names of UTF-16 surrogate character test fixture constants, see also #1326. Thanks to IBue, Gary Gregory.
+o Moditect plugin generates split package warnings. Thanks to Gary Gregory.
+o LocaleUtils.availableLocaleSet() uses predictable iteration order. Thanks to Gary Gregory.
+o LANG-1759: SerializationUtils.clone(Object) throws ClassCastException when called with a Serializable lambda. Thanks to Maxim Butov, Gary Gregory.
+o LANG-1759: [StringUtils::indexOfAnyBut] redesign due to inconsistent/faulty behavior regarding UTF-16 surrogates #1327. Thanks to IBue, Gary Gregory, Piotr P. Karwasz.
+o Undeprecate ObjectUtils.toString(Object). Thanks to Gary Gregory.
+o Fix Spotbugs [ERROR] Medium: The field org.apache.commons.lang3.builder.DiffBuilder$SDiff.leftSupplier is transient but isn't set by deserialization [org.apache.commons.lang3.builder.DiffBuilder$SDiff] In DiffBuilder.java SE_TRANSIENT_FIELD_NOT_RESTORED. Thanks to Gary Gregory.
+o Fix Spotbugs [ERROR] Medium: The field org.apache.commons.lang3.builder.DiffBuilder$SDiff.rightSupplier is transient but isn't set by deserialization [org.apache.commons.lang3.builder.DiffBuilder$SDiff] In DiffBuilder.java SE_TRANSIENT_FIELD_NOT_RESTORED. Thanks to Gary Gregory.
+o LANG-1762: StopWatch methods should not delegate to deprecated methods. Thanks to Alonso Gonzalez, Gary Gregory.
+o Don't call TypeUtils.toString(Type) on every array item in TypeUtils.parameterize[WithOwner](Type, Class, Map, Type>) unless required. Thanks to Gary Gregory.
+o Remove -nouses directive from maven-bundle-plugin. OSGi package imports now state 'uses' definitions for package imports, this doesn't affect JPMS (from org.apache.commons:commons-parent:80). Thanks to Gary Gregory.
+o Instead of throwing a NullPointerException, ArrayUtils.toStringArray(Object[]) should return "null" for null elements like ArrayUtils.toStringArray(Object[], String) returns its valueForNullElements. Thanks to Gary Gregory.
+o LANG-1764: Deprecate NumericEntityUnescaper.OPTION in favor of Apache Commons Text. Thanks to Gary Gregory.
+o Several hash collisions in Fraction class. Thanks to Gary Gregory.
+o LANG-1768: MutableLong and friends should provide better parsing exceptions Javadocs. Thanks to Wang Hailong, Gary Gregory.
+o Reimplement StringUtils.toCodePoints(CharSequence) to use java.lang.CharSequence.codePoints(). Thanks to Gary Gregory.
+o Reimplement StringUtils.capitalize(String) to use java.lang.CharSequence.codePoints(). Thanks to Gary Gregory.
+o Reimplement StringUtils.uncapitalize(String) to use java.lang.CharSequence.codePoints(). Thanks to Gary Gregory.
+o org.apache.commons.lang3.ClassUtils.getCanonicalName(String) now throws an IllegalArgumentException for array dimensions greater than 255. Thanks to Gary Gregory.
+o Fix Javadoc typo and improve clarity in defaultIfBlank method #1376. Thanks to Sridhar Balijepalli, Piotr P. Karwasz.
+o LANG-1773: Apache Commons Lang no longer builds on Android #1381. Thanks to Éamonn McManus, Gary Gregory.
+o LANG-1772: Restrict size of cache to prevent overflow errors #1379. Thanks to James Winters, Piotr P. Karwasz, Gary Gregory.
+o LANG-1772: Reimplement org.apache.commons.lang3.ClassUtils.hierarchy(Class, Interfaces) using an AtomicReference. Thanks to Gary Gregory.
+o Fix Javadoc code examples in DiffBuilder and ReflectionDiffBuilder #1400. Thanks to Ken Dombeck.
+o Fix generics in org.apache.commons.lang3.stream.Streams.toArray(Class) signature. Thanks to Gary Gregory.
+o LANG-1727: EventListenerSupport doesn't document ordering of events. Thanks to Elliotte Rusty Harold, Gary Gregory.
+o Fix edge-case NullPointerException in org.apache.commons.lang3.SystemUtils.IS_OS_ANDROID. Thanks to Gary Gregory.
+o Fix edge-case NullPointerException in org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast(JavaVersion). Thanks to Gary Gregory.
+o Fix edge-case NullPointerException in org.apache.commons.lang3.SystemUtils.isJavaVersionAtMost(JavaVersion). Thanks to Gary Gregory.
+o Return the default enum if a SecurityException is caught in getEnumSystemProperty(). Thanks to Gary Gregory.
+o Fix edge-case NullPointerException in org.apache.commons.lang3.EnumUtils.getEnum(Class, String, E). Thanks to Gary Gregory.
+o org.apache.commons.lang3.EnumUtils.getFirstEnumIgnoreCase(Class, String, Function, E) now returns the given default enum on null enumClass input. Thanks to Gary Gregory.
+o org.apache.commons.lang3.EnumUtils.getEnumIgnoreCase(Class, String, E) now returns the given default enum on null enumClass input. Thanks to Gary Gregory.
+o org.apache.commons.lang3.EnumUtils.getEnumIgnoreCase(Class, String) now returns the given default enum on null enumClass input. Thanks to Gary Gregory.
+o Fix NullPointerException in org.apache.commons.lang3.compare.ComparableUtils.ComparableCheckBuilder.equalTo(A). Thanks to Gary Gregory.
+o Fix NullPointerException in org.apache.commons.lang3.compare.ComparableUtils.ComparableCheckBuilder.greaterThan(A). Thanks to Gary Gregory.
+o Fix NullPointerException in org.apache.commons.lang3.compare.ComparableUtils.ComparableCheckBuilder.greaterThanOrEqualTo(A). Thanks to Gary Gregory.
+o Fix NullPointerException in org.apache.commons.lang3.compare.ComparableUtils.ComparableCheckBuilder.lessThan(A). Thanks to Gary Gregory.
+o Fix NullPointerException in org.apache.commons.lang3.compare.ComparableUtils.ComparableCheckBuilder.lessThanOrEqualTo(A). Thanks to Gary Gregory.
+o LANG-1776: Use GitHub URL in POM for improved automation support.
+
+Changes:
+o Bump org.apache.commons:commons-parent from 73 to 85 #1267, #1277, #1283, #1288, #1302, #1377. Thanks to Gary Gregory, Dependabot.
+o [site] Bump org.codehaus.mojo:taglist-maven-plugin from 3.1.0 to 3.2.1 #1300. Thanks to Gary Gregory, Dependabot.
+o [test] Bump org.easymock:easymock from 5.4.0 to 5.6.0 #1317, #1387. Thanks to Gary Gregory, Dependabot.
+o [test] Bump org.apache.commons:commons-text from 1.12.0 to 1.13.1 #1336. Thanks to Gary Gregory, Dependabot.
+
+
+Historical list of changes: https://commons.apache.org/proper/commons-lang/changes.html
+
+For complete information on Apache Commons Lang, including instructions on how to submit bug reports,
+patches, or suggestions for improvement, see the Apache Commons Lang website:
+
+https://commons.apache.org/proper/commons-lang/
+
+Download page: https://commons.apache.org/proper/commons-lang/download_lang.cgi
+
+Have fun!
+Apache Commons Team
+
+-----------------------------------------------------------------------------
+
+Apache Commons Lang 3.17.0 Release Notes
+----------------------------------------
+
+The Apache Commons team is pleased to announce Apache Commons Lang Version 3.17.0.
+
+Commons Lang is a set of utility functions and reusable components that should be useful in any Java environment.
+
+Starting with Commons Lang 3.9, we target Java 8, using those features.
+
+For advice on upgrading from 2.x to 3.x, see:
+
+ https://commons.apache.org/lang/article3_0.html
+
+Apache Commons Lang, a package of Java utility classes for the
+classes that are in java.lang's hierarchy, or are considered to be so
+standard as to justify existence in java.lang.
+
+The code is tested using the latest revision of the JDK for supported
+LTS releases: 8, 11, 17 and 21 currently.
+See https://github.com/apache/commons-lang/blob/master/.github/workflows/maven.yml
+
+Please ensure your build environment is up-to-date and kindly report any build issues.
+
+This is a feature and maintenance release. Java 8 or later is required.
+
+Changes in this version include:
+
+New features:
+o RandomUtils.secure() now uses SecureRandom() instead of SecureRandom.getInstanceStrong(). Thanks to Gary Gregory.
+o RandomStringUtils.secure() now uses SecureRandom() instead of SecureRandom.getInstanceStrong(). Thanks to Gary Gregory.
+o Remove unused exception from deprecated StringUtils.toString(byte[], String). Thanks to Gary Gregory.
+o Make RandomUtils.insecure() public. Thanks to Gary Gregory.
+o Add RandomUtils.secureStrong(). Thanks to Gary Gregory.
+o Add RandomStringUtils.secureStrong(). Thanks to Gary Gregory.
+o Add CalendarUtils.toLocalDateTime(Calendar). Thanks to Gary Gregory.
+o Add CalendarUtils.toLocalDateTime(). Thanks to Gary Gregory.
+o Add CalendarUtils.toZonedDateTime(Calendar). Thanks to Gary Gregory.
+o Add CalendarUtils.toZonedDateTime(). Thanks to Gary Gregory.
+o Add CalendarUtils.toOffsetDateTime(Calendar). Thanks to Gary Gregory.
+o Add CalendarUtils.toOffsetDateTime(). Thanks to Gary Gregory.
+
+Fixed Bugs:
+o LANG-1760: Using RandomStringUtils.insecure() still leads to using the secure() random. Thanks to Marco Hoek, Gary Gregory.
+o Deprecate static RandomUtils.next*() methods in favor or .secure() and .insecure() versions. Thanks to Gary Gregory.
+o Deprecate static RandomStringUtils.random*() methods in favor or .secure() and .insecure() versions. Thanks to Gary Gregory.
+
+Changes:
+o Bump org.hamcrest:hamcrest from 2.2 to 3.0 #1255. Thanks to Gary Gregory, Dependabot.
+o Bump org.easymock:easymock from 5.3.0 to 5.4.0 #1256. Thanks to Gary Gregory, Dependabot.
+o Bump org.codehaus.mojo:exec-maven-plugin from 3.3.0 to 3.4.1 #1262, #1264. Thanks to Gary Gregory, Dependabot.
+o Bump org.apache.commons:commons-parent from 72 to 73 #1265. Thanks to Gary Gregory, Dependabot.
+
+
+Historical list of changes: https://commons.apache.org/proper/commons-lang/changes-report.html
+
+For complete information on Apache Commons Lang, including instructions on how to submit bug reports,
+patches, or suggestions for improvement, see the Apache Commons Lang website:
+
+https://commons.apache.org/proper/commons-lang/
+
+Download page: https://commons.apache.org/proper/commons-lang/download_lang.cgi
+
+Have fun!
+Apache Commons Team
+
+-----------------------------------------------------------------------------
+
+Apache Commons Lang 3.16.0 Release Notes
+----------------------------------------
+
+The Apache Commons team is pleased to announce Apache Commons Lang Version 3.16.0.
+
+Commons Lang is a set of utility functions and reusable components that should be useful in any Java environment.
+
+Starting with Commons Lang 3.9, we target Java 8, using those features.
+
+For advice on upgrading from 2.x to 3.x, see:
+
+ https://commons.apache.org/lang/article3_0.html
+
+Apache Commons Lang, a package of Java utility classes for the
+classes that are in java.lang's hierarchy, or are considered to be so
+standard as to justify existence in java.lang.
+
+The code is tested using the latest revision of the JDK for supported
+LTS releases: 8, 11, 17 and 21 currently.
+See https://github.com/apache/commons-lang/blob/master/.github/workflows/maven.yml
+
+Please ensure your build environment is up-to-date and kindly report any build issues.
+
+This is a feature and maintenance release. Java 8 or later is required.
+
+Changes in this version include:
+
+New features:
+o Add StopWatch.getSplitDuration() and deprecate getSplitTime(). Thanks to Gary Gregory.
+o Add StopWatch.getStartInstant() and deprecate getStartTime(). Thanks to Gary Gregory.
+o Add StopWatch.getStopInstant() and deprecate getStopTime(). Thanks to Gary Gregory.
+o Add StopWatch.getDuration() and deprecate getTime(). Thanks to Gary Gregory.
+o Add Javadoc links from StopWatch to DurationUtils #1249. Thanks to Oliver B. Fischer, Gary Gregory.
+o Add LangCollectors.collect(Collector, T...). Thanks to Gary Gregory.
+o Add RandomStringUtils.secure(). Thanks to Gary Gregory.
+o Add RandomStringUtils.insecure(). Thanks to Gary Gregory.
+
+Fixed Bugs:
+o Reimplement StopWatch internals to use java.time. Thanks to Gary Gregory.
+o LANG-1745: RandomStringUtils.random() with a negative character index should throw IllegalArgumentException. Thanks to Wang Hailong, Gary Gregory.
+o LANG-1741: LocaleUtils.toLocale(String) cannot parse four segments. Thanks to Wang Hailong, Gary Gregory.
+o Use fewer intermediary strings in DefaultExceptionContext.getFormattedExceptionMessage(String). Thanks to Gary Gregory.
+o Fix Javadoc in StringUtils.splitPreserveAllTokens() #1251. Thanks to VīŋŊclav Haisman.
+o Deprecate ArraySort constructor for removal. Thanks to Gary Gregory.
+o Deprecate CharEncoding constructor for removal. Thanks to Gary Gregory.
+o Deprecate Conversion constructor for removal. Thanks to Gary Gregory.
+o Deprecate Conversion constructor for removal. Thanks to Gary Gregory.
+o Deprecate EntityArrays constructor for removal. Thanks to Gary Gregory.
+o Deprecate ObjectToStringComparator constructor for removal. Thanks to Gary Gregory.
+o Deprecate RuntimeEnvironment constructor for removal. Thanks to Gary Gregory.
+
+Changes:
+o Bump org.apache.commons:commons-parent from 71 to 72 #1253. Thanks to Gary Gregory, Dependabot.
+
+
+Historical list of changes: https://commons.apache.org/proper/commons-lang/changes-report.html
+
+For complete information on Apache Commons Lang, including instructions on how to submit bug reports,
+patches, or suggestions for improvement, see the Apache Commons Lang website:
+
+https://commons.apache.org/proper/commons-lang/
+
+Download page: https://commons.apache.org/proper/commons-lang/download_lang.cgi
+
+Have fun!
+Apache Commons Team
+
+-----------------------------------------------------------------------------
+
+Apache Commons Lang 3.15.0 Release Notes
+----------------------------------------
+
+The Apache Commons team is pleased to announce Apache Commons Lang Version 3.15.0.
+
+Commons Lang is a set of utility functions and reusable components that should be of use in any Java environment.
+
+Starting with Commons Lang 3.9, we target Java 8, making use of those features.
+
+For advice on upgrading from 2.x to 3.x, see:
+
+ https://commons.apache.org/lang/article3_0.html
+
+Apache Commons Lang, a package of Java utility classes for the
+classes that are in java.lang's hierarchy, or are considered to be so
+standard as to justify existence in java.lang.
+
+The code is tested using the latest revision of the JDK for supported
+LTS releases: 8, 11, 17 and 21 currently.
+See https://github.com/apache/commons-lang/blob/master/.github/workflows/maven.yml
+
+Please ensure your build environment is up-to-date and kindly report any build issues.
+
+New features and bug fixes (Java 8 or above).
+
+Changes in this version include:
+
+New features:
+o LANG-1724: Customize text pattern in DiffResult#toString(). Thanks to Gary Gregory, Dennis Baerten.
+o Add DiffBuilder.Builder. Thanks to Gary Gregory.
+o Add DiffBuilder.builder(). Thanks to Gary Gregory.
+o Add ReflectionDiffBuilder.Builder. Thanks to Gary Gregory.
+o Add ReflectionDiffBuilder.builder(). Thanks to Gary Gregory.
+o Add test in TypeUtilsTest #1151. Thanks to Elliotte Rusty Harold.
+o Add Streams.failableStream(T), non-varargs variant. Thanks to Gary Gregory.
+o Add Streams.nonNull(T), non-varargs variant. Thanks to Gary Gregory.
+o Add ArrayUtils.nullTo(T[], T[]). Thanks to Gary Gregory.
+o Add T ArrayUtils.arraycopy(T, int, T, int, int) fluent style. Thanks to Gary Gregory.
+o Add T ArrayUtils.arraycopy(T, int, int, int, Function) fluent style. Thanks to Gary Gregory.
+o Add SystemUtils.IS_JAVA_22. Thanks to Gary Gregory.
+o Add JavaVersion.JAVA_22. Thanks to Gary Gregory.
+o Add SystemProperties.getUserName(Supplier). Thanks to Gary Gregory.
+o Add SystemProperties.getLineSeparator(Supplier). Thanks to Gary Gregory.
+o Add SystemProperties.getJavaSpecificationVersion(Supplier). Thanks to Gary Gregory.
+o Add SystemProperties constants and methods for system properties as of Java 22. Thanks to Gary Gregory.
+o Add MethodUtils.getMethodObject(Class, String, Class...). Thanks to Gary Gregory.
+o LANG-1733: Add null-safe Consumers.accept() and Functions.apply() #1215. Thanks to Jongjin Bae, Gary Gregory.
+o Add SystemUtils.IS_OS_ANDROID. Thanks to Gary Gregory.
+o Add SystemUtils.IS_OS_MAC_OSX_SONOMA. Thanks to Gary Gregory.
+o Add RuntimeEnvironment.inContainer() #1241. Thanks to Gary Gregory.
+o Add AppendableJoiner and refactor string joining #1244. Thanks to Gary Gregory.
+
+Fixed Bugs:
+o Improve Javadoc in ExceptionUtils #1136. Thanks to MiklīŋŊs KarakīŋŊ, Gary Gregory.
+o Fixed two non-deterministic tests in EnumUtilsTest.java #1131. Thanks to Saiharshith Karuneegar Ramesh, Gary Gregory.
+o LANG-1721: Fix wrong number check that cause StringIndexOutOfBoundsException #1140. Thanks to Arthur Chan, Gary Gregory.
+o LANG-1722: Rethrow NegativeArraySizeException as SerializationException in SerializationUtils.deserialize(InputStream) #1141. Thanks to Arthur Chan.
+o LANG-1723: Throw NumberFormatException instead of IndexOutOfBoundsException in NumberUtils.getMantissa(String, int) #1145. Thanks to Arthur Chan, Gary Gregory.
+o Minor grammar fixes #1143. Thanks to ParanoīŋŊd User.
+o LANG-1713: ArrayUtils will return null when adding two null arrays, but undocumented. Thanks to John Hendrikx, Gary Gregory.
+o Let parent POM figure out commons.spdx.version. Thanks to Gary Gregory.
+o LANG-1726: Undeprecate ExceptionUtils.rethrow(Throwable). Thanks to VīŋŊclav Haisman, Gary Gregory.
+o LANG-1702: Test the Conversion class #1155. Thanks to Elliotte Rusty Harold.
+o Address minor redundancies after code inspection #1148. Thanks to ParanoidUser, Elliotte Rusty Harold, Gary Gregory.
+o Allow EventListenerSupport to handle (and ignore) exception from listeners allowing invocation of all listeners #1167. Thanks to Gary Gregory.
+o Deprecate AnnotationUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate ArchUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate ArrayUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate BooleanUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate CharSequenceUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate CharSetUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate CharUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate ClassLoaderUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate ClassPathUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate ClassUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate ConstructorUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate DateFormatUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate DateUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate Diff.getType(). Thanks to Gary Gregory.
+o Deprecate DiffBuilder.DiffBuilder(T, T, ToStringStyle). Thanks to Gary Gregory.
+o Deprecate DiffBuilder.DiffBuilder(T, T, ToStringStyle, boolean). Thanks to Gary Gregory.
+o Deprecate DurationFormatUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate DurationUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate EnumUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate EventUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate FieldUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate IEEE754rUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate InheritanceUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate IntStreams 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate LocaleUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate LockingVisitors 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate MemberUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate MethodUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate NumberUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate ObjectUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate RandomStringUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate RandomUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate ReflectionDiffBuilder.ReflectionDiffBuilder(T, T, ToStringStyle). Thanks to Gary Gregory.
+o Deprecate RegExUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate SerializationUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate Streams 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate StringEscapeUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate StringUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate Suppliers 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate SystemProperties 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate ThreadUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate TypeUtils 0-argument constructor. Thanks to Gary Gregory.
+o Make ArrayFill null-safe. Thanks to Gary Gregory.
+o Make ArraySorter null-safe. Thanks to Gary Gregory.
+o Make ArrayUtils.removeAll() null-safe. Thanks to Gary Gregory.
+o Fix Java version in README.md #1170. Thanks to Philipp Trulson, Gary Gregory.
+o StringUtils.stripAccents() should handle ligatures, UTF32 math blocks, etc. #1201. Thanks to Stephan Peters, Gary Gregory, Bernd.
+o LANG-1524: TypeUtils.toString(Type) StackOverflowError for an inner class in the inner class parameterized enclosing class #657. Thanks to kijong.youn, Aakash Gupta, Gary Gregory.
+o Deprecate SystemUtils.getUserName(String) in favor of SystemProperties.getUserName(Supplier). Thanks to Gary Gregory.
+o Make LockVisitor.acceptReadLocked(FailableConsumer) null-safe. Thanks to Gary Gregory.
+o Make LockVisitor.applyWriteLocked(FailableConsumer) null-safe. Thanks to Gary Gregory.
+o Make ObjectUtils.getFirstNonNull(Supplier...) null-safe. Thanks to Gary Gregory.
+o Make SystemProperties.getLineSeparator(Supplier). Thanks to Gary Gregory.
+o StringUtils.stripAccents(String) doesn't handle "\u0111" and "\u0110" (Vietnamese) #1216. Thanks to hunghhdev.
+o StringUtils.stripAccents(String) doesn't handle I with bar. Thanks to Gary Gregory.
+o StringUtils.stripAccents(String) doesn't handle U with bar. Thanks to Gary Gregory.
+o StringUtils.stripAccents(String) doesn't handle T with stroke. Thanks to Gary Gregory.
+o LANG-1735: Fix Javadoc for FluentBitSet.setInclusive(int, int) #1222. Thanks to Tobias Kiecker.
+o Same Javadoc changes as [TEXT-234] #1223. Thanks to Tobias Kiecker.
+o Remove duplicate static data in SerializationUtils.ClassLoaderAwareObjectInputStream. Thanks to Gary Gregory.
+o Reimplement RandomUtils and RandomStringUtils on top of SecureRandom#getInstanceStrong() #1235. Thanks to Gary Gregory, Henri Yandell, Fabrice Benhamouda.
+o LANG-1657: DiffBuilder: Type constraint for method append(..., DiffResult) too strict #786. Thanks to Matthias Welz, Andrew Thomas, Gary Gregory.
+
+Changes:
+o Bump commons-parent from 64 to 71 #1194, #1233. Thanks to Dependabot, Gary Gregory.
+o Bump org.codehaus.mojo:exec-maven-plugin from 3.1.1 to 3.3.0 #1175, #1224. Thanks to Dependabot.
+o Bump org.apache.commons:commons-text from 1.11.0 to 1.12.0 #1200. Thanks to Dependabot.
+o Bump org.easymock:easymock from 5.2.0 to 5.3.0 #1232. Thanks to Dependabot.
+o Bump org.codehaus.mojo:taglist-maven-plugin from 3.0.0 to 3.1.0 #1242. Thanks to Dependabot.
+
+Removed:
+o Drop obsolete JDK 13 Maven profile #1142. Thanks to ParanoīŋŊd User.
+
+Historical list of changes: https://commons.apache.org/proper/commons-lang/changes-report.html
+
+For complete information on Apache Commons Lang, including instructions on how to submit bug reports,
+patches, or suggestions for improvement, see the Apache Commons Lang website:
+
+https://commons.apache.org/proper/commons-lang/
+
+Download page: https://commons.apache.org/proper/commons-lang/download_lang.cgi
+
+Have fun!
+-Apache Commons Team
+
+-----------------------------------------------------------------------------
+
+Apache Commons Lang 3.14.0 Release Notes
+----------------------------------------
+
+This document contains the release notes for the 3.14.0 version of Apache Commons Lang.
+Commons Lang is a set of utility functions and reusable components that should be of use in any
+Java environment.
+
+Lang 3.9 and onwards now targets Java 8, making use of features that arrived with Java 8.
+
+For the advice on upgrading from 2.x to 3.x, see the following page:
+
+ https://commons.apache.org/lang/article3_0.html
+
+Apache Commons Lang, a package of Java utility classes for the
+classes that are in java.lang's hierarchy, or are considered to be so
+standard as to justify existence in java.lang.
+
+New features and bug fixes (Java 8 or above).
+
+Changes in this version include:
+
+New features:
+o Add Functions#function(Function). Thanks to Rob Spoor, Gary Gregory.
+o Add FailableFunction#function(FailableFunction). Thanks to Rob Spoor, Gary Gregory.
+o Add CalendarUtils.getInstance(). Thanks to Gary Gregory.
+o Add syntax for optional tokens to DurationFormatUtils #1062. Thanks to Dan Watson.
+o Add ArrayFill. Thanks to Gary Gregory.
+o Add FastDateParser.TimeZoneStrategy.TzInfo.toString(). Thanks to Gary Gregory.
+o Add LocaleUtils.isLanguageUndetermined(Locale). Thanks to Gary Gregory.
+o Add ObjectUtils.toString(Supplier
*
*
#ThreadSafe#
+ *
* @since 2.1
*/
public class CharUtils {
- private static final String[] CHAR_STRING_ARRAY = new String[128];
+ private static final String[] CHAR_STRING_ARRAY = ArrayUtils.setAll(new String[128], i -> String.valueOf((char) i));
private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
/**
- * {@code \u000a} linefeed LF ('\n').
+ * Linefeed character LF ({@code '\n'}, Unicode 000a).
*
- * @see JLF: Escape Sequences
+ * @see JLF: Escape Sequences
* for Character and String Literals
* @since 2.2
*/
public static final char LF = '\n';
/**
- * {@code \u000d} carriage return CR ('\r').
+ * Carriage return character CR ('\r', Unicode 000d).
*
- * @see JLF: Escape Sequences
+ * @see JLF: Escape Sequences
* for Character and String Literals
* @since 2.2
*/
@@ -57,89 +60,287 @@ public class CharUtils {
*/
public static final char NUL = '\0';
- static {
- for (char c = 0; c < CHAR_STRING_ARRAY.length; c++) {
- CHAR_STRING_ARRAY[c] = String.valueOf(c);
- }
+ /**
+ * Compares two {@code char} values numerically. This is the same functionality as provided in Java 7.
+ *
+ * @param x The first {@code char} to compare
+ * @param y The second {@code char} to compare
+ * @return The value {@code 0} if {@code x == y};
+ * a value less than {@code 0} if {@code x < y}; and
+ * a value greater than {@code 0} if {@code x > y}
+ * @since 3.4
+ */
+ public static int compare(final char x, final char y) {
+ return x - y;
}
/**
- *
{@code CharUtils} instances should NOT be constructed in standard programming.
- * Instead, the class should be used as {@code CharUtils.toString('c');}.
+ * Tests whether the character is ASCII 7 bit.
*
- *
This constructor is public to permit tools that require a JavaBean instance
- * to operate.
+ *
+ * @param ch The character to check
+ * @return true if between 65 and 90 or 97 and 122 inclusive
+ */
+ public static boolean isAsciiAlpha(final char ch) {
+ return isAsciiAlphaUpper(ch) || isAsciiAlphaLower(ch);
+ }
+
+ /**
+ * Tests whether the character is ASCII 7 bit alphabetic lower case.
*
*
*
- * @deprecated Java 5 introduced {@link Character#valueOf(char)} which caches chars 0 through 127.
- * @param ch the character to convert
- * @return a Character of the specified character
+ * @param ch The character to check
+ * @return true if between 97 and 122 inclusive
*/
- @Deprecated
- public static Character toCharacterObject(final char ch) {
- return Character.valueOf(ch);
+ public static boolean isAsciiAlphaLower(final char ch) {
+ return ch >= 'a' && ch <= 'z';
}
/**
- *
Converts the String to a Character using the first character, returning
- * null for empty Strings.
+ * Tests whether the character is ASCII 7 bit alphanumeric character.
*
- *
For ASCII 7 bit characters, this uses a cache that will return the
- * same Character object each time.
+ *
+ * @param ch The character to check
+ * @return true if between 48 and 57 or 65 and 90 or 97 and 122 inclusive
+ */
+ public static boolean isAsciiAlphanumeric(final char ch) {
+ return isAsciiAlpha(ch) || isAsciiNumeric(ch);
+ }
+
+ /**
+ * Tests whether the character is ASCII 7 bit alphabetic upper case.
*
*
*
- * @param str the character to convert
- * @return the Character value of the first letter of the String
+ * @param ch The character to check
+ * @return true if between 65 and 90 inclusive
*/
- public static Character toCharacterObject(final String str) {
- if (StringUtils.isEmpty(str)) {
- return null;
- }
- return Character.valueOf(str.charAt(0));
+ public static boolean isAsciiAlphaUpper(final char ch) {
+ return ch >= 'A' && ch <= 'Z';
+ }
+
+ /**
+ * Tests whether the character is ASCII 7 bit control.
+ *
+ *
+ *
+ * @param ch The character to check
+ * @return true if less than 32 or equals 127
+ */
+ public static boolean isAsciiControl(final char ch) {
+ return ch < 32 || ch == 127;
+ }
+
+ /**
+ * Tests whether the character is ASCII 7 bit numeric.
+ *
+ *
+ *
+ * @param ch The code point to test.
+ * @return true if character is a hexadecimal character.
+ * @since 3.21.0
+ */
+ public static boolean isHex(final int ch) {
+ return isAsciiNumeric(ch) || ch >= 'a' && ch <= 'f' || ch >= 'A' && ch <= 'F';
+ }
+
+ /**
+ * Tests if the given char is an octal digit. Octal digits are the character representations of the digits 0 to 7.
+ *
+ * @param ch The byte to check.
+ * @return true if the given char is the character representation of one of the digits from 0 to 7.
+ * @since 3.21.0
+ */
+ public static boolean isOctal(final byte ch) {
+ return ch >= '0' && ch <= '7';
+ }
+
+ /**
+ * Tests if the given char is an octal digit. Octal digits are the character representations of the digits 0 to 7.
+ *
+ * @param ch The char to check.
+ * @return true if the given char is the character representation of one of the digits from 0 to 7.
+ * @since 3.18.0
+ */
+ public static boolean isOctal(final char ch) {
+ return ch >= '0' && ch <= '7';
}
- //-----------------------------------------------------------------------
/**
- *
Converts the Character to a char throwing an exception for {@code null}.
+ * Converts the Character to a char throwing an exception for {@code null}.
*
*
*
- * @param ch the character to convert
- * @return the char value of the Character
- * @throws IllegalArgumentException if the Character is null
+ * @param ch The character to convert
+ * @return The char value of the Character
+ * @throws NullPointerException if the Character is null
*/
public static char toChar(final Character ch) {
- Validate.isTrue(ch != null, "The Character must not be null");
- return ch.charValue();
+ return Objects.requireNonNull(ch, "ch").charValue();
}
/**
- *
Converts the Character to a char handling {@code null}.
+ * Converts the Character to a char handling {@code null}.
*
*
*
- * @param ch the character to convert
- * @param defaultValue the value to use if the Character is null
- * @return the char value of the Character or the default if null
+ * @param ch The character to convert
+ * @param defaultValue The value to use if the Character is null
+ * @return The char value of the Character or the default if null
*/
public static char toChar(final Character ch, final char defaultValue) {
- if (ch == null) {
- return defaultValue;
- }
- return ch.charValue();
+ return ch != null ? ch.charValue() : defaultValue;
}
- //-----------------------------------------------------------------------
/**
- *
Converts the String to a char using the first character, throwing
- * an exception on empty Strings.
+ * Converts the String to a char using the first character, throwing
+ * an exception on empty Strings.
*
*
*
- * @param str the character to convert
- * @return the char value of the first letter of the String
+ * @param str The character to convert
+ * @return The char value of the first letter of the String
+ * @throws NullPointerException if the string is null
* @throws IllegalArgumentException if the String is empty
*/
public static char toChar(final String str) {
- Validate.isTrue(StringUtils.isNotEmpty(str), "The String must not be empty");
+ Validate.notEmpty(str, "The String must not be empty");
return str.charAt(0);
}
/**
- *
Converts the String to a char using the first character, defaulting
- * the value on empty Strings.
+ * Converts the String to a char using the first character, defaulting
+ * the value on empty Strings.
*
*
*
- * @param str the character to convert
- * @param defaultValue the value to use if the Character is null
- * @return the char value of the first letter of the String or the default if null
+ * @param str The character to convert
+ * @param defaultValue The value to use if the Character is null
+ * @return The char value of the first letter of the String or the default if null
*/
public static char toChar(final String str, final char defaultValue) {
- if (StringUtils.isEmpty(str)) {
- return defaultValue;
- }
- return str.charAt(0);
+ return StringUtils.isEmpty(str) ? defaultValue : str.charAt(0);
+ }
+
+ /**
+ * Delegates to {@link Character#valueOf(char)}.
+ *
+ * @param c The character to convert
+ * @return A {@code Character} representing {@code c}.
+ * @deprecated Use {@link Character#valueOf(char)}.
+ */
+ @Deprecated
+ public static Character toCharacterObject(final char c) {
+ return Character.valueOf(c);
+ }
+
+ /**
+ * Converts the String to a Character using the first character, returning
+ * null for empty Strings.
+ *
+ *
For ASCII 7 bit characters, this uses a cache that will return the
+ * same Character object each time.
+ *
+ * @param str The character to convert
+ * @return The Character value of the first letter of the String
+ */
+ public static Character toCharacterObject(final String str) {
+ return StringUtils.isEmpty(str) ? null : Character.valueOf(str.charAt(0));
}
- //-----------------------------------------------------------------------
/**
- *
Converts the character to the Integer it represents, throwing an
- * exception if the character is not numeric.
+ * Converts the character to the Integer it represents, throwing an
+ * exception if the character is not numeric.
*
*
This method converts the char '1' to the int 1 and so on.
*
@@ -213,8 +440,8 @@ public static char toChar(final String str, final char defaultValue) {
* CharUtils.toIntValue('A') throws IllegalArgumentException
*
*
- * @param ch the character to convert
- * @return the int value of the character
+ * @param ch The character to convert
+ * @return The int value of the character
* @throws IllegalArgumentException if the character is not ASCII numeric
*/
public static int toIntValue(final char ch) {
@@ -225,8 +452,8 @@ public static int toIntValue(final char ch) {
}
/**
- *
Converts the character to the Integer it represents, throwing an
- * exception if the character is not numeric.
+ * Converts the character to the Integer it represents, throwing an
+ * exception if the character is not numeric.
*
*
This method converts the char '1' to the int 1 and so on.
*
@@ -235,41 +462,38 @@ public static int toIntValue(final char ch) {
* CharUtils.toIntValue('A', -1) = -1
*
*
- * @param ch the character to convert
- * @param defaultValue the default value to use if the character is not numeric
- * @return the int value of the character
+ * @param ch The character to convert
+ * @param defaultValue The default value to use if the character is not numeric
+ * @return The int value of the character
*/
public static int toIntValue(final char ch, final int defaultValue) {
- if (!isAsciiNumeric(ch)) {
- return defaultValue;
- }
- return ch - 48;
+ return isAsciiNumeric(ch) ? ch - 48 : defaultValue;
}
/**
- *
Converts the character to the Integer it represents, throwing an
- * exception if the character is not numeric.
+ * Converts the character to the Integer it represents, throwing an
+ * exception if the character is not numeric.
*
*
This method converts the char '1' to the int 1 and so on.
*
- * @param ch the character to convert, not null
- * @return the int value of the character
- * @throws IllegalArgumentException if the Character is not ASCII numeric or is null
+ * @param ch The character to convert, not null
+ * @return The int value of the character
+ * @throws NullPointerException if the Character is null
+ * @throws IllegalArgumentException if the Character is not ASCII numeric
*/
public static int toIntValue(final Character ch) {
- Validate.isTrue(ch != null, "The character must not be null");
- return toIntValue(ch.charValue());
+ return toIntValue(toChar(ch));
}
/**
- *
Converts the character to the Integer it represents, throwing an
- * exception if the character is not numeric.
+ * Converts the character to the Integer it represents, throwing an
+ * exception if the character is not numeric.
*
*
This method converts the char '1' to the int 1 and so on.
*
@@ -279,20 +503,16 @@ public static int toIntValue(final Character ch) {
* CharUtils.toIntValue('A', -1) = -1
*
*
- * @param ch the character to convert
- * @param defaultValue the default value to use if the character is not numeric
- * @return the int value of the character
+ * @param ch The character to convert
+ * @param defaultValue The default value to use if the character is not numeric
+ * @return The int value of the character
*/
public static int toIntValue(final Character ch, final int defaultValue) {
- if (ch == null) {
- return defaultValue;
- }
- return toIntValue(ch.charValue(), defaultValue);
+ return ch != null ? toIntValue(ch.charValue(), defaultValue) : defaultValue;
}
- //-----------------------------------------------------------------------
/**
- *
Converts the character to a String that contains the one character.
+ * Converts the character to a String that contains the one character.
*
*
For ASCII 7 bit characters, this uses a cache that will return the
* same String object each time.
@@ -302,18 +522,18 @@ public static int toIntValue(final Character ch, final int defaultValue) {
* CharUtils.toString('A') = "A"
*
*
- * @param ch the character to convert
- * @return a String containing the one specified character
+ * @param ch The character to convert
+ * @return A String containing the one specified character
*/
public static String toString(final char ch) {
- if (ch < 128) {
+ if (ch < CHAR_STRING_ARRAY.length) {
return CHAR_STRING_ARRAY[ch];
}
- return new String(new char[] {ch});
+ return String.valueOf(ch);
}
/**
- *
Converts the character to a String that contains the one character.
+ * Converts the character to a String that contains the one character.
*
*
For ASCII 7 bit characters, this uses a cache that will return the
* same String object each time.
@@ -326,19 +546,15 @@ public static String toString(final char ch) {
* CharUtils.toString('A') = "A"
*
*
- * @param ch the character to convert
- * @return a String containing the one specified character
+ * @param ch The character to convert
+ * @return A String containing the one specified character
*/
public static String toString(final Character ch) {
- if (ch == null) {
- return null;
- }
- return toString(ch.charValue());
+ return ch != null ? toString(ch.charValue()) : null;
}
- //--------------------------------------------------------------------------
/**
- *
Converts the string to the Unicode format '\u0020'.
+ * Converts the string to the Unicode format '\u0020'.
*
*
+ * {@link CharUtils} instances should NOT be constructed in standard programming.
+ * Instead, the class should be used as {@code CharUtils.toString('c');}.
*
- * @param ch the character to check
- * @return true if between 48 and 57 or 65 and 90 or 97 and 122 inclusive
- */
- public static boolean isAsciiAlphanumeric(final char ch) {
- return isAsciiAlpha(ch) || isAsciiNumeric(ch);
- }
-
- /**
- *
Compares two {@code char} values numerically. This is the same functionality as provided in Java 7.
+ *
This constructor is public to permit tools that require a JavaBean instance
+ * to operate.
*
- * @param x the first {@code char} to compare
- * @param y the second {@code char} to compare
- * @return the value {@code 0} if {@code x == y};
- * a value less than {@code 0} if {@code x < y}; and
- * a value greater than {@code 0} if {@code x > y}
- * @since 3.4
+ * @deprecated TODO Make private in 4.0.
*/
- public static int compare(final char x, final char y) {
- return x-y;
+ @Deprecated
+ public CharUtils() {
+ // empty
}
}
diff --git a/src/main/java/org/apache/commons/lang3/Charsets.java b/src/main/java/org/apache/commons/lang3/Charsets.java
index c80bb90a377..7f7c2ebe45d 100644
--- a/src/main/java/org/apache/commons/lang3/Charsets.java
+++ b/src/main/java/org/apache/commons/lang3/Charsets.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -32,13 +32,13 @@
*
* @since 3.10
*/
-class Charsets {
+final class Charsets {
/**
* Returns the given {@code charset} or the default Charset if {@code charset} is null.
*
- * @param charset a Charset or null.
- * @return the given {@code charset} or the default Charset if {@code charset} is null.
+ * @param charset A Charset or null.
+ * @return The given {@code charset} or the default Charset if {@code charset} is null.
*/
static Charset toCharset(final Charset charset) {
return charset == null ? Charset.defaultCharset() : charset;
@@ -47,8 +47,8 @@ static Charset toCharset(final Charset charset) {
/**
* Returns the given {@code charset} or the default Charset if {@code charset} is null.
*
- * @param charsetName a Charset or null.
- * @return the given {@code charset} or the default Charset if {@code charset} is null.
+ * @param charsetName A Charset or null.
+ * @return The given {@code charset} or the default Charset if {@code charset} is null.
* @throws UnsupportedCharsetException If no support for the named charset is available in this instance of the Java
* virtual machine
*/
@@ -59,8 +59,8 @@ static Charset toCharset(final String charsetName) {
/**
* Returns the given {@code charset} or the default Charset if {@code charset} is null.
*
- * @param charsetName a Charset or null.
- * @return the given {@code charset} or the default Charset if {@code charset} is null.
+ * @param charsetName A Charset or null.
+ * @return The given {@code charset} or the default Charset if {@code charset} is null.
*/
static String toCharsetName(final String charsetName) {
return charsetName == null ? Charset.defaultCharset().name() : charsetName;
diff --git a/src/main/java/org/apache/commons/lang3/ClassLoaderUtils.java b/src/main/java/org/apache/commons/lang3/ClassLoaderUtils.java
index 95cdd2aabab..a970508dad1 100644
--- a/src/main/java/org/apache/commons/lang3/ClassLoaderUtils.java
+++ b/src/main/java/org/apache/commons/lang3/ClassLoaderUtils.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -17,8 +17,10 @@
package org.apache.commons.lang3;
+import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
+import java.util.Objects;
/**
* Helps work with {@link ClassLoader}.
@@ -27,27 +29,62 @@
*/
public class ClassLoaderUtils {
+ private static final URL[] EMPTY_URL_ARRAY = {};
+
+ /**
+ * Gets the system class loader's URLs, if any.
+ *
+ * @return The system class loader's URLs, if any.
+ * @since 3.13.0
+ */
+ public static URL[] getSystemURLs() {
+ return getURLs(ClassLoader.getSystemClassLoader());
+ }
+
+ /**
+ * Gets the current thread's context class loader's URLs, if any.
+ *
+ * @return The current thread's context class loader's URLs, if any.
+ * @since 3.13.0
+ */
+ public static URL[] getThreadURLs() {
+ return getURLs(Thread.currentThread().getContextClassLoader());
+ }
+
+ private static URL[] getURLs(final ClassLoader cl) {
+ return cl instanceof URLClassLoader ? ((URLClassLoader) cl).getURLs() : EMPTY_URL_ARRAY;
+ }
+
/**
* Converts the given class loader to a String calling {@link #toString(URLClassLoader)}.
*
* @param classLoader to URLClassLoader to convert.
- * @return the formated string.
+ * @return The formatted string.
*/
public static String toString(final ClassLoader classLoader) {
if (classLoader instanceof URLClassLoader) {
return toString((URLClassLoader) classLoader);
}
- return classLoader.toString();
+ return Objects.toString(classLoader);
}
/**
- * Converts the given URLClassLoader to a String in the format
- * {@code "URLClassLoader.toString() + [URL1, URL2, ...]"}.
+ * Converts the given URLClassLoader to a String in the format {@code "URLClassLoader.toString() + [URL1, URL2, ...]"}.
*
* @param classLoader to URLClassLoader to convert.
- * @return the formated string.
+ * @return The formatted string.
*/
public static String toString(final URLClassLoader classLoader) {
- return classLoader + Arrays.toString(classLoader.getURLs());
+ return classLoader != null ? classLoader + Arrays.toString(classLoader.getURLs()) : "null";
+ }
+
+ /**
+ * Make private in 4.0.
+ *
+ * @deprecated TODO Make private in 4.0.
+ */
+ @Deprecated
+ public ClassLoaderUtils() {
+ // empty
}
}
diff --git a/src/main/java/org/apache/commons/lang3/ClassPathUtils.java b/src/main/java/org/apache/commons/lang3/ClassPathUtils.java
index df3773a344c..4956ce08eec 100644
--- a/src/main/java/org/apache/commons/lang3/ClassPathUtils.java
+++ b/src/main/java/org/apache/commons/lang3/ClassPathUtils.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -16,10 +16,14 @@
*/
package org.apache.commons.lang3;
+import java.util.Objects;
+
/**
* Operations regarding the classpath.
*
- *
The methods of this class do not allow {@code null} inputs.
+ *
+ * The methods of this class do not allow {@code null} inputs.
+ *
*
* @since 3.3
*/
@@ -27,104 +31,130 @@
public class ClassPathUtils {
/**
- *
{@code ClassPathUtils} instances should NOT be constructed in
- * standard programming. Instead, the class should be used as
- * {@code ClassPathUtils.toFullyQualifiedName(MyClass.class, "MyClass.properties");}.
+ * Converts a package name to a Java path ('/').
*
- *
This constructor is public to permit tools that require a JavaBean
- * instance to operate.
+ * @param path The source path.
+ * @return A package name.
+ * @throws NullPointerException if {@code path} is null.
+ * @since 3.13.0
*/
- public ClassPathUtils() {
- super();
+ public static String packageToPath(final String path) {
+ return Objects.requireNonNull(path, "path").replace('.', '/');
+ }
+
+ /**
+ * Converts a Java path ('/') to a package name.
+ *
+ * @param path The source path.
+ * @return A package name.
+ * @throws NullPointerException if {@code path} is null.
+ * @since 3.13.0
+ */
+ public static String pathToPackage(final String path) {
+ return Objects.requireNonNull(path, "path").replace('/', '.');
}
/**
* Returns the fully qualified name for the resource with name {@code resourceName} relative to the given context.
*
- *
Note that this method does not check whether the resource actually exists.
- * It only constructs the name.
- * Null inputs are not allowed.
+ *
+ * Note that this method does not check whether the resource actually exists. It only constructs the name. Null inputs are not allowed.
+ *
*
- * @param context The context for constructing the name.
- * @param resourceName the resource name to construct the fully qualified name for.
- * @return the fully qualified name of the resource with name {@code resourceName}.
- * @throws java.lang.NullPointerException if either {@code context} or {@code resourceName} is null.
+ * @param context The context for constructing the name.
+ * @param resourceName The resource name to construct the fully qualified name for.
+ * @return The fully qualified name of the resource with name {@code resourceName}.
+ * @throws NullPointerException if either {@code context} or {@code resourceName} is null.
*/
public static String toFullyQualifiedName(final Class> context, final String resourceName) {
- Validate.notNull(context, "Parameter '%s' must not be null!", "context" );
- Validate.notNull(resourceName, "Parameter '%s' must not be null!", "resourceName");
+ Objects.requireNonNull(context, "context");
+ Objects.requireNonNull(resourceName, "resourceName");
return toFullyQualifiedName(context.getPackage(), resourceName);
}
/**
* Returns the fully qualified name for the resource with name {@code resourceName} relative to the given context.
*
- *
Note that this method does not check whether the resource actually exists.
- * It only constructs the name.
- * Null inputs are not allowed.
+ *
+ * Note that this method does not check whether the resource actually exists. It only constructs the name. Null inputs are not allowed.
+ *
*
- * @param context The context for constructing the name.
- * @param resourceName the resource name to construct the fully qualified name for.
- * @return the fully qualified name of the resource with name {@code resourceName}.
- * @throws java.lang.NullPointerException if either {@code context} or {@code resourceName} is null.
+ * @param context The context for constructing the name.
+ * @param resourceName The resource name to construct the fully qualified name for.
+ * @return The fully qualified name of the resource with name {@code resourceName}.
+ * @throws NullPointerException if either {@code context} or {@code resourceName} is null.
*/
public static String toFullyQualifiedName(final Package context, final String resourceName) {
- Validate.notNull(context, "Parameter '%s' must not be null!", "context" );
- Validate.notNull(resourceName, "Parameter '%s' must not be null!", "resourceName");
+ Objects.requireNonNull(context, "context");
+ Objects.requireNonNull(resourceName, "resourceName");
return context.getName() + "." + resourceName;
}
/**
* Returns the fully qualified path for the resource with name {@code resourceName} relative to the given context.
*
- *
Note that this method does not check whether the resource actually exists.
- * It only constructs the path.
- * Null inputs are not allowed.
+ *
+ * Note that this method does not check whether the resource actually exists. It only constructs the path. Null inputs are not allowed.
+ *
*
- * @param context The context for constructing the path.
- * @param resourceName the resource name to construct the fully qualified path for.
- * @return the fully qualified path of the resource with name {@code resourceName}.
- * @throws java.lang.NullPointerException if either {@code context} or {@code resourceName} is null.
+ * @param context The context for constructing the path.
+ * @param resourceName The resource name to construct the fully qualified path for.
+ * @return The fully qualified path of the resource with name {@code resourceName}.
+ * @throws NullPointerException if either {@code context} or {@code resourceName} is null.
*/
public static String toFullyQualifiedPath(final Class> context, final String resourceName) {
- Validate.notNull(context, "Parameter '%s' must not be null!", "context" );
- Validate.notNull(resourceName, "Parameter '%s' must not be null!", "resourceName");
+ Objects.requireNonNull(context, "context");
+ Objects.requireNonNull(resourceName, "resourceName");
return toFullyQualifiedPath(context.getPackage(), resourceName);
}
-
/**
* Returns the fully qualified path for the resource with name {@code resourceName} relative to the given context.
*
- *
Note that this method does not check whether the resource actually exists.
- * It only constructs the path.
- * Null inputs are not allowed.
+ *
+ * Note that this method does not check whether the resource actually exists. It only constructs the path. Null inputs are not allowed.
+ *
*
- * @param context The context for constructing the path.
- * @param resourceName the resource name to construct the fully qualified path for.
- * @return the fully qualified path of the resource with name {@code resourceName}.
- * @throws java.lang.NullPointerException if either {@code context} or {@code resourceName} is null.
+ * @param context The context for constructing the path.
+ * @param resourceName The resource name to construct the fully qualified path for.
+ * @return The fully qualified path of the resource with name {@code resourceName}.
+ * @throws NullPointerException if either {@code context} or {@code resourceName} is null.
*/
public static String toFullyQualifiedPath(final Package context, final String resourceName) {
- Validate.notNull(context, "Parameter '%s' must not be null!", "context" );
- Validate.notNull(resourceName, "Parameter '%s' must not be null!", "resourceName");
- return context.getName().replace('.', '/') + "/" + resourceName;
+ Objects.requireNonNull(context, "context");
+ Objects.requireNonNull(resourceName, "resourceName");
+ return packageToPath(context.getName()) + "/" + resourceName;
+ }
+
+ /**
+ * {@link ClassPathUtils} instances should NOT be constructed in standard programming. Instead, the class should be used as
+ * {@code ClassPathUtils.toFullyQualifiedName(MyClass.class, "MyClass.properties");}.
+ *
+ *
+ * This constructor is public to permit tools that require a JavaBean instance to operate.
+ *
+ *
+ * @deprecated TODO Make private in 4.0.
+ */
+ @Deprecated
+ public ClassPathUtils() {
+ // empty
}
}
diff --git a/src/main/java/org/apache/commons/lang3/ClassUtils.java b/src/main/java/org/apache/commons/lang3/ClassUtils.java
index 4b90ab2973e..302d6269c54 100644
--- a/src/main/java/org/apache/commons/lang3/ClassUtils.java
+++ b/src/main/java/org/apache/commons/lang3/ClassUtils.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -18,41 +18,82 @@
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Comparator;
+import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
-
-import org.apache.commons.lang3.mutable.MutableObject;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
/**
- *
Operates on classes without using reflection.
+ * Operates on classes without using reflection.
*
- *
This class handles invalid {@code null} inputs as best it can.
- * Each method documents its behaviour in more detail.
+ *
+ * This class handles invalid {@code null} inputs as best it can. Each method documents its behavior in more detail.
+ *
*
- *
The notion of a {@code canonical name} includes the human
- * readable name for the type, for example {@code int[]}. The
- * non-canonical method variants work with the JVM names, such as
- * {@code [I}.
+ *
+ * The notion of a {@code canonical name} includes the human-readable name for the type, for example {@code int[]}. The
+ * non-canonical method variants work with the JVM names, such as {@code [I}.
+ *
*
* @since 2.0
*/
public class ClassUtils {
/**
- * Inclusivity literals for {@link #hierarchy(Class, Interfaces)}.
+ * Enumerates inclusivity literals for {@link #hierarchy(Class, Interfaces)}.
+ *
* @since 3.2
*/
public enum Interfaces {
- INCLUDE, EXCLUDE
+
+ /** Includes interfaces. */
+ INCLUDE,
+
+ /** Excludes interfaces. */
+ EXCLUDE
}
+ /**
+ * The JLS-specified maximum class name length {@value}.
+ *
+ * @see Class#forName(String, boolean, ClassLoader)
+ * @see JVM: Array dimension limits in JVM Specification CONSTANT_Class_info
+ * @see JLS: Fully Qualified Names and Canonical Names
+ * @see JLS: The Form of a Binary
+ */
+ private static final int MAX_CLASS_NAME_LENGTH = 65535;
+
+ /**
+ * The JVM-specified {@code CONSTANT_Class_info} structure defines an array type descriptor is valid only if it represents {@value} or fewer dimensions.
+ *
+ * @see Class#forName(String, boolean, ClassLoader)
+ * @see JVM: Array dimension limits in JVM Specification CONSTANT_Class_info
+ * @see JLS: Fully Qualified Names and Canonical Names
+ * @see JLS: The Form of a Binary
+ */
+ private static final int MAX_JVM_ARRAY_DIMENSION = 255;
+
+ /**
+ * The maximum number of array dimensions.
+ */
+ private static final int MAX_DIMENSIONS = 255;
+
+ private static final Pattern ARRAY_TAIL_PATTERN = Pattern.compile("(?:\\[\\])+");
+
+ private static final Comparator> COMPARATOR = (o1, o2) -> Objects.compare(getName(o1), getName(o2), String::compareTo);
+
/**
* The package separator character: {@code '.' == {@value}}.
*/
@@ -74,411 +115,217 @@ public enum Interfaces {
public static final String INNER_CLASS_SEPARATOR = String.valueOf(INNER_CLASS_SEPARATOR_CHAR);
/**
- * Maps names of primitives to their corresponding primitive {@code Class}es.
+ * Maps names of primitives to their corresponding primitive {@link Class}es.
*/
- private static final Map> namePrimitiveMap = new HashMap<>();
+ private static final Map> NAME_PRIMITIVE_MAP = new HashMap<>();
+
static {
- namePrimitiveMap.put("boolean", Boolean.TYPE);
- namePrimitiveMap.put("byte", Byte.TYPE);
- namePrimitiveMap.put("char", Character.TYPE);
- namePrimitiveMap.put("short", Short.TYPE);
- namePrimitiveMap.put("int", Integer.TYPE);
- namePrimitiveMap.put("long", Long.TYPE);
- namePrimitiveMap.put("double", Double.TYPE);
- namePrimitiveMap.put("float", Float.TYPE);
- namePrimitiveMap.put("void", Void.TYPE);
+ NAME_PRIMITIVE_MAP.put(Boolean.TYPE.getName(), Boolean.TYPE);
+ NAME_PRIMITIVE_MAP.put(Byte.TYPE.getName(), Byte.TYPE);
+ NAME_PRIMITIVE_MAP.put(Character.TYPE.getName(), Character.TYPE);
+ NAME_PRIMITIVE_MAP.put(Double.TYPE.getName(), Double.TYPE);
+ NAME_PRIMITIVE_MAP.put(Float.TYPE.getName(), Float.TYPE);
+ NAME_PRIMITIVE_MAP.put(Integer.TYPE.getName(), Integer.TYPE);
+ NAME_PRIMITIVE_MAP.put(Long.TYPE.getName(), Long.TYPE);
+ NAME_PRIMITIVE_MAP.put(Short.TYPE.getName(), Short.TYPE);
+ NAME_PRIMITIVE_MAP.put(Void.TYPE.getName(), Void.TYPE);
}
/**
- * Maps primitive {@code Class}es to their corresponding wrapper {@code Class}.
+ * Maps primitive {@link Class}es to their corresponding wrapper {@link Class}.
*/
- private static final Map, Class>> primitiveWrapperMap = new HashMap<>();
+ private static final Map, Class>> PRIMITIVE_WRAPPER_MAP = new HashMap<>();
+
static {
- primitiveWrapperMap.put(Boolean.TYPE, Boolean.class);
- primitiveWrapperMap.put(Byte.TYPE, Byte.class);
- primitiveWrapperMap.put(Character.TYPE, Character.class);
- primitiveWrapperMap.put(Short.TYPE, Short.class);
- primitiveWrapperMap.put(Integer.TYPE, Integer.class);
- primitiveWrapperMap.put(Long.TYPE, Long.class);
- primitiveWrapperMap.put(Double.TYPE, Double.class);
- primitiveWrapperMap.put(Float.TYPE, Float.class);
- primitiveWrapperMap.put(Void.TYPE, Void.TYPE);
+ PRIMITIVE_WRAPPER_MAP.put(Boolean.TYPE, Boolean.class);
+ PRIMITIVE_WRAPPER_MAP.put(Byte.TYPE, Byte.class);
+ PRIMITIVE_WRAPPER_MAP.put(Character.TYPE, Character.class);
+ PRIMITIVE_WRAPPER_MAP.put(Short.TYPE, Short.class);
+ PRIMITIVE_WRAPPER_MAP.put(Integer.TYPE, Integer.class);
+ PRIMITIVE_WRAPPER_MAP.put(Long.TYPE, Long.class);
+ PRIMITIVE_WRAPPER_MAP.put(Double.TYPE, Double.class);
+ PRIMITIVE_WRAPPER_MAP.put(Float.TYPE, Float.class);
+ PRIMITIVE_WRAPPER_MAP.put(Void.TYPE, Void.TYPE);
}
/**
- * Maps wrapper {@code Class}es to their corresponding primitive types.
+ * Maps wrapper {@link Class}es to their corresponding primitive types.
*/
- private static final Map, Class>> wrapperPrimitiveMap = new HashMap<>();
+ private static final Map, Class>> WRAPPER_PRIMITIVE_MAP = new HashMap<>();
+
static {
- for (final Map.Entry, Class>> entry : primitiveWrapperMap.entrySet()) {
- final Class> primitiveClass = entry.getKey();
- final Class> wrapperClass = entry.getValue();
+ PRIMITIVE_WRAPPER_MAP.forEach((primitiveClass, wrapperClass) -> {
if (!primitiveClass.equals(wrapperClass)) {
- wrapperPrimitiveMap.put(wrapperClass, primitiveClass);
+ WRAPPER_PRIMITIVE_MAP.put(wrapperClass, primitiveClass);
}
- }
+ });
}
/**
* Maps a primitive class name to its corresponding abbreviation used in array class names.
*/
- private static final Map abbreviationMap;
+ private static final Map ABBREVIATION_MAP;
/**
* Maps an abbreviation used in array class names to corresponding primitive class name.
*/
- private static final Map reverseAbbreviationMap;
- // Feed abbreviation maps
- static {
- final Map m = new HashMap<>();
- m.put("int", "I");
- m.put("boolean", "Z");
- m.put("float", "F");
- m.put("long", "J");
- m.put("short", "S");
- m.put("byte", "B");
- m.put("double", "D");
- m.put("char", "C");
- final Map r = new HashMap<>();
- for (final Map.Entry e : m.entrySet()) {
- r.put(e.getValue(), e.getKey());
- }
- abbreviationMap = Collections.unmodifiableMap(m);
- reverseAbbreviationMap = Collections.unmodifiableMap(r);
- }
+ private static final Map REVERSE_ABBREVIATION_MAP;
- /**
- *
ClassUtils instances should NOT be constructed in standard programming.
- * Instead, the class should be used as
- * {@code ClassUtils.getShortClassName(cls)}.
- *
- *
This constructor is public to permit tools that require a JavaBean
- * instance to operate.
Gets the class name of the {@code object} without the package name or names.
- *
- *
The method looks up the class of the object and then converts the name of the class invoking
- * {@link #getShortClassName(Class)} (see relevant notes there).
+ * Gets the class comparator, comparing by class name.
*
- * @param object the class to get the short name for, may be {@code null}
- * @param valueIfNull the value to return if the object is {@code null}
- * @return the class name of the object without the package name, or {@code valueIfNull}
- * if the argument {@code object} is {@code null}
+ * @return The class comparator.
+ * @since 3.13.0
*/
- public static String getShortClassName(final Object object, final String valueIfNull) {
- if (object == null) {
- return valueIfNull;
- }
- return getShortClassName(object.getClass());
+ public static Comparator> comparator() {
+ return COMPARATOR;
}
/**
- *
Gets the class name minus the package name from a {@code Class}.
+ * Given a {@link List} of {@link Class} objects, this method converts them into class names.
*
- *
This method simply gets the name using {@code Class.getName()} and then calls
- * {@link #getShortClassName(Class)}. See relevant notes there.
+ *
+ * A new {@link List} is returned. {@code null} objects will be copied into the returned list as {@code null}.
+ *
*
- * @param cls the class to get the short name for.
- * @return the class name without the package name or an empty string. If the class
- * is an inner class then the returned value will contain the outer class
- * or classes separated with {@code .} (dot) character.
+ * @param classes The classes to change.
+ * @return A {@link List} of class names corresponding to the Class objects, {@code null} if null input.
+ * @throws ClassCastException if {@code classes} contains a non-{@link Class} entry.
*/
- public static String getShortClassName(final Class> cls) {
- if (cls == null) {
- return StringUtils.EMPTY;
- }
- return getShortClassName(cls.getName());
+ public static List convertClassesToClassNames(final List> classes) {
+ return classes == null ? null : classes.stream().map(e -> getName(e, null)).collect(Collectors.toList());
}
/**
- *
Gets the class name minus the package name from a String.
- *
- *
The string passed in is assumed to be a class name - it is not checked. The string has to be formatted the way
- * as the JDK method {@code Class.getName()} returns it, and not the usual way as we write it, for example in import
- * statements, or as it is formatted by {@code Class.getCanonicalName()}.
- *
- *
The difference is is significant only in case of classes that are inner classes of some other
- * classes. In this case the separator between the outer and inner class (possibly on multiple hierarchy level) has
- * to be {@code $} (dollar sign) and not {@code .} (dot), as it is returned by {@code Class.getName()}
- *
- *
Note that this method is called from the {@link #getShortClassName(Class)} method using the string
- * returned by {@code Class.getName()}.
+ * Given a {@link List} of class names, this method converts them into classes.
*
- *
Note that this method differs from {@link #getSimpleName(Class)} in that this will
- * return, for example {@code "Map.Entry"} whilst the {@code java.lang.Class} variant will simply
- * return {@code "Entry"}. In this example the argument {@code className} is the string
- * {@code java.util.Map$Entry} (note the {@code $} sign.
+ *
+ * A new {@link List} is returned. If the class name cannot be found, {@code null} is stored in the {@link List}. If the
+ * class name in the {@link List} is {@code null}, {@code null} is stored in the output {@link List}.
+ *
*
- * @param className the className to get the short name for. It has to be formatted as returned by
- * {@code Class.getName()} and not {@code Class.getCanonicalName()}
- * @return the class name of the class without the package name or an empty string. If the class is
- * an inner class then value contains the outer class or classes and the separator is replaced
- * to be {@code .} (dot) character.
+ * @param classNames The classNames to change.
+ * @return A {@link List} of Class objects corresponding to the class names, {@code null} if null input.
+ * @throws ClassCastException if classNames contains a non String entry.
*/
- public static String getShortClassName(String className) {
- if (StringUtils.isEmpty(className)) {
- return StringUtils.EMPTY;
+ public static List> convertClassNamesToClasses(final List classNames) {
+ if (classNames == null) {
+ return null;
}
-
- final StringBuilder arrayPrefix = new StringBuilder();
-
- // Handle array encoding
- if (className.startsWith("[")) {
- while (className.charAt(0) == '[') {
- className = className.substring(1);
- arrayPrefix.append("[]");
- }
- // Strip Object type encoding
- if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') {
- className = className.substring(1, className.length() - 1);
- }
-
- if (reverseAbbreviationMap.containsKey(className)) {
- className = reverseAbbreviationMap.get(className);
+ final List> classes = new ArrayList<>(classNames.size());
+ classNames.forEach(className -> {
+ try {
+ classes.add(Class.forName(className));
+ } catch (final Exception ex) {
+ classes.add(null);
}
- }
-
- final int lastDotIdx = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR);
- final int innerIdx = className.indexOf(
- INNER_CLASS_SEPARATOR_CHAR, lastDotIdx == -1 ? 0 : lastDotIdx + 1);
- String out = className.substring(lastDotIdx + 1);
- if (innerIdx != -1) {
- out = out.replace(INNER_CLASS_SEPARATOR_CHAR, PACKAGE_SEPARATOR_CHAR);
- }
- return out + arrayPrefix;
- }
-
- /**
- *
Null-safe version of {@code cls.getSimpleName()}
- *
- * @param cls the class for which to get the simple name; may be null
- * @return the simple class name or the empty string in case the argument is {@code null}
- * @since 3.0
- * @see Class#getSimpleName()
- */
- public static String getSimpleName(final Class> cls) {
- return getSimpleName(cls, StringUtils.EMPTY);
- }
-
- /**
- *
Null-safe version of {@code cls.getSimpleName()}
- *
- * @param cls the class for which to get the simple name; may be null
- * @param valueIfNull the value to return if null
- * @return the simple class name or {@code valueIfNull} if the
- * argument {@code cls} is {@code null}
- * @since 3.0
- * @see Class#getSimpleName()
- */
- public static String getSimpleName(final Class> cls, String valueIfNull) {
- return cls == null ? valueIfNull : cls.getSimpleName();
- }
-
- /**
- *
Null-safe version of {@code object.getClass().getSimpleName()}
- *
- *
It is to note that this method is overloaded and in case the argument {@code object} is a
- * {@code Class} object then the {@link #getSimpleName(Class)} will be invoked. If this is
- * a significant possibility then the caller should check this case and call {@code
- * getSimpleName(Class.class)} or just simply use the string literal {@code "Class"}, which
- * is the result of the method in that case.
- *
- * @param object the object for which to get the simple class name; may be null
- * @return the simple class name or the empty string in case the argument is {@code null}
- * @since 3.7
- * @see Class#getSimpleName()
- */
- public static String getSimpleName(final Object object) {
- return getSimpleName(object, StringUtils.EMPTY);
- }
-
- /**
- *
Null-safe version of {@code object.getClass().getSimpleName()}
- *
- * @param object the object for which to get the simple class name; may be null
- * @param valueIfNull the value to return if {@code object} is {@code null}
- * @return the simple class name or {@code valueIfNull} if the
- * argument {@code object} is {@code null}
- * @since 3.0
- * @see Class#getSimpleName()
- */
- public static String getSimpleName(final Object object, final String valueIfNull) {
- return object == null ? valueIfNull : object.getClass().getSimpleName();
- }
-
- /**
- *
Null-safe version of {@code cls.getName()}
- *
- * @param cls the class for which to get the class name; may be null
- * @return the class name or the empty string in case the argument is {@code null}
- * @since 3.7
- * @see Class#getSimpleName()
- */
- public static String getName(final Class> cls) {
- return getName(cls, StringUtils.EMPTY);
- }
-
- /**
- *
Null-safe version of {@code cls.getName()}
- *
- * @param cls the class for which to get the class name; may be null
- * @param valueIfNull the return value if the argument {@code cls} is {@code null}
- * @return the class name or {@code valueIfNull}
- * @since 3.7
- * @see Class#getName()
- */
- public static String getName(final Class> cls, final String valueIfNull) {
- return cls == null ? valueIfNull : cls.getName();
- }
-
- /**
- *
Null-safe version of {@code object.getClass().getName()}
- *
- * @param object the object for which to get the class name; may be null
- * @return the class name or the empty String
- * @since 3.7
- * @see Class#getSimpleName()
- */
- public static String getName(final Object object) {
- return getName(object, StringUtils.EMPTY);
- }
-
- /**
- *
Null-safe version of {@code object.getClass().getSimpleName()}
- *
- * @param object the object for which to get the class name; may be null
- * @param valueIfNull the value to return if {@code object} is {@code null}
- * @return the class name or {@code valueIfNull}
- * @since 3.0
- * @see Class#getName()
- */
- public static String getName(final Object object, final String valueIfNull) {
- return object == null ? valueIfNull : object.getClass().getName();
- }
-
- // Package name
- // ----------------------------------------------------------------------
- /**
- *
Gets the package name of an {@code Object}.
- *
- * @param object the class to get the package name for, may be null
- * @param valueIfNull the value to return if null
- * @return the package name of the object, or the null value
- */
- public static String getPackageName(final Object object, final String valueIfNull) {
- if (object == null) {
- return valueIfNull;
- }
- return getPackageName(object.getClass());
- }
-
- /**
- *
Gets the package name of a {@code Class}.
- *
- * @param cls the class to get the package name for, may be {@code null}.
- * @return the package name or an empty string
- */
- public static String getPackageName(final Class> cls) {
- if (cls == null) {
- return StringUtils.EMPTY;
- }
- return getPackageName(cls.getName());
- }
-
- /**
- *
Gets the package name from a {@code String}.
- *
- *
The string passed in is assumed to be a class name - it is not checked.
- *
If the class is unpackaged, return an empty string.
- *
- * @param className the className to get the package name for, may be {@code null}
- * @return the package name or an empty string
- */
- public static String getPackageName(String className) {
- if (StringUtils.isEmpty(className)) {
- return StringUtils.EMPTY;
- }
-
- // Strip array encoding
- while (className.charAt(0) == '[') {
- className = className.substring(1);
- }
- // Strip Object type encoding
- if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') {
- className = className.substring(1);
- }
-
- final int i = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR);
- if (i == -1) {
- return StringUtils.EMPTY;
- }
- return className.substring(0, i);
+ });
+ return classes;
}
- // Abbreviated name
- // ----------------------------------------------------------------------
/**
- *
Gets the abbreviated name of a {@code Class}.
+ * Gets the abbreviated name of a {@link Class}.
*
- * @param cls the class to get the abbreviated name for, may be {@code null}
- * @param lengthHint the desired length of the abbreviated name
- * @return the abbreviated name or an empty string
- * @throws IllegalArgumentException if len <= 0
+ * @param cls The class to get the abbreviated name for, may be {@code null}.
+ * @param lengthHint The desired length of the abbreviated name.
+ * @return The abbreviated name or an empty string.
+ * @throws IllegalArgumentException if len <= 0.
* @see #getAbbreviatedName(String, int)
* @since 3.4
*/
public static String getAbbreviatedName(final Class> cls, final int lengthHint) {
- if (cls == null) {
- return StringUtils.EMPTY;
- }
- return getAbbreviatedName(cls.getName(), lengthHint);
+ if (cls == null) {
+ return StringUtils.EMPTY;
+ }
+ return getAbbreviatedName(cls.getName(), lengthHint);
}
/**
- *
Gets the abbreviated class name from a {@code String}.
+ * Gets the abbreviated class name from a {@link String}.
*
- *
The string passed in is assumed to be a class name - it is not checked.
+ *
+ * The string passed in is assumed to be a class name - it is not checked.
+ *
*
- *
The abbreviation algorithm will shorten the class name, usually without
- * significant loss of meaning.
+ *
+ * The abbreviation algorithm will shorten the class name, usually without significant loss of meaning.
+ *
*
- *
The abbreviated class name will always include the complete package hierarchy.
- * If enough space is available, rightmost sub-packages will be displayed in full
- * length. The abbreviated package names will be shortened to a single character.
- *
Only package names are shortened, the class simple name remains untouched. (See examples.)
- *
The result will be longer than the desired length only if all the package names
- * shortened to a single character plus the class simple name with the separating dots
- * together are longer than the desired length. In other words, when the class name
- * cannot be shortened to the desired length.
- *
If the class name can be shortened then
- * the final length will be at most {@code lengthHint} characters.
- *
If the {@code lengthHint} is zero or negative then the method
- * throws exception. If you want to achieve the shortest possible version then
- * use {@code 1} as a {@code lengthHint}.
+ *
+ * The abbreviated class name will always include the complete package hierarchy. If enough space is available,
+ * rightmost sub-packages will be displayed in full length. The abbreviated package names will be shortened to a single
+ * character.
+ *
+ *
+ * Only package names are shortened, the class simple name remains untouched. (See examples.)
+ *
+ *
+ * The result will be longer than the desired length only if all the package names shortened to a single character plus
+ * the class simple name with the separating dots together are longer than the desired length. In other words, when the
+ * class name cannot be shortened to the desired length.
+ *
+ *
+ * If the class name can be shortened then the final length will be at most {@code lengthHint} characters.
+ *
+ *
+ * If the {@code lengthHint} is zero or negative then the method throws exception. If you want to achieve the shortest
+ * possible version then use {@code 1} as a {@code lengthHint}.
+ *
*
*
*
Examples
- *
className
len
return
- *
null
1
""
- *
"java.lang.String"
5
"j.l.String"
- *
"java.lang.String"
15
"j.lang.String"
- *
"java.lang.String"
30
"java.lang.String"
- *
"org.apache.commons.lang3.ClassUtils"
18
"o.a.c.l.ClassUtils"
+ *
+ *
className
+ *
len
+ *
return
+ *
+ *
+ *
null
+ *
1
+ *
""
+ *
+ *
+ *
"java.lang.String"
+ *
5
+ *
"j.l.String"
+ *
+ *
+ *
"java.lang.String"
+ *
15
+ *
"j.lang.String"
+ *
+ *
+ *
"java.lang.String"
+ *
30
+ *
"java.lang.String"
+ *
+ *
+ *
"org.apache.commons.lang3.ClassUtils"
+ *
18
+ *
"o.a.c.l.ClassUtils"
+ *
*
*
- * @param className the className to get the abbreviated name for, may be {@code null}
- * @param lengthHint the desired length of the abbreviated name
- * @return the abbreviated name or an empty string if the specified
- * class name is {@code null} or empty string. The abbreviated name may be
- * longer than the desired length if it cannot be abbreviated to the desired length.
- * @throws IllegalArgumentException if {@code len <= 0}
+ * @param className The className to get the abbreviated name for, may be {@code null}.
+ * @param lengthHint The desired length of the abbreviated name.
+ * @return The abbreviated name or an empty string if the specified class name is {@code null} or empty string. The
+ * abbreviated name may be longer than the desired length if it cannot be abbreviated to the desired length.
+ * @throws IllegalArgumentException if {@code len <= 0}.
* @since 3.4
*/
public static String getAbbreviatedName(final String className, final int lengthHint) {
@@ -502,8 +349,7 @@ public static String getAbbreviatedName(final String className, final int length
}
++target;
- if (useFull(runAheadTarget, source, abbreviated.length, lengthHint)
- || target > runAheadTarget) {
+ if (useFull(runAheadTarget, source, abbreviated.length, lengthHint) || target > runAheadTarget) {
target = runAheadTarget;
}
@@ -516,1046 +362,1513 @@ public static String getAbbreviatedName(final String className, final int length
}
/**
- *
Decides if the part that was just copied to its destination
- * location in the work array can be kept as it was copied or must be
- * abbreviated. It must be kept when the part is the last one, which
- * is the simple name of the class. In this case the {@code source}
- * index, from where the characters are copied points one position
- * after the last character, a.k.a. {@code source ==
- * originalLength}
- *
- *
If the part is not the last one then it can be kept
- * unabridged if the number of the characters copied so far plus
- * the character that are to be copied is less than or equal to the
- * desired length.
- *
- * @param runAheadTarget the target index (where the characters were
- * copied to) pointing after the last character
- * copied when the current part was copied
- * @param source the source index (where the characters were
- * copied from) pointing after the last
- * character copied when the current part was
- * copied
- * @param originalLength the original length of the class full name,
- * which is abbreviated
- * @param desiredLength the desired length of the abbreviated class
- * name
- * @return {@code true} if it can be kept in its original length
- * {@code false} if the current part has to be abbreviated and
- */
- private static boolean useFull(final int runAheadTarget,
- final int source,
- final int originalLength,
- final int desiredLength) {
- return source >= originalLength ||
- runAheadTarget + originalLength - source <= desiredLength;
- }
-
- // Superclasses/Superinterfaces
- // ----------------------------------------------------------------------
- /**
- *
Gets a {@code List} of superclasses for the given class.
- *
- * @param cls the class to look up, may be {@code null}
- * @return the {@code List} of superclasses in order going up from this one
- * {@code null} if null input
- */
- public static List> getAllSuperclasses(final Class> cls) {
- if (cls == null) {
- return null;
- }
- final List> classes = new ArrayList<>();
- Class> superclass = cls.getSuperclass();
- while (superclass != null) {
- classes.add(superclass);
- superclass = superclass.getSuperclass();
- }
- return classes;
- }
-
- /**
- *
Gets a {@code List} of all interfaces implemented by the given
- * class and its superclasses.
+ * Gets a {@link List} of all interfaces implemented by the given class and its superclasses.
*
- *
The order is determined by looking through each interface in turn as
- * declared in the source file and following its hierarchy up. Then each
- * superclass is considered in the same way. Later duplicates are ignored,
- * so the order is maintained.
+ *
+ * The order is determined by looking through each interface in turn as declared in the source file and following its
+ * hierarchy up. Then each superclass is considered in the same way. Later duplicates are ignored, so the order is
+ * maintained.
+ *
*
- * @param cls the class to look up, may be {@code null}
- * @return the {@code List} of interfaces in order,
- * {@code null} if null input
+ * @param cls The class to look up, may be {@code null}.
+ * @return The {@link List} of interfaces in order, {@code null} if null input.
*/
public static List> getAllInterfaces(final Class> cls) {
if (cls == null) {
return null;
}
-
final LinkedHashSet> interfacesFound = new LinkedHashSet<>();
getAllInterfaces(cls, interfacesFound);
-
return new ArrayList<>(interfacesFound);
}
/**
- * Get the interfaces for the specified class.
+ * Gets the interfaces for the specified class.
*
- * @param cls the class to look up, may be {@code null}
- * @param interfacesFound the {@code Set} of interfaces for the class
+ * @param cls The class to look up, may be {@code null}.
+ * @param interfacesFound The {@link Set} of interfaces for the class.
*/
- private static void getAllInterfaces(Class> cls, final HashSet> interfacesFound) {
+ private static void getAllInterfaces(Class> cls, final Set> interfacesFound) {
while (cls != null) {
- final Class>[] interfaces = cls.getInterfaces();
-
- for (final Class> i : interfaces) {
+ for (final Class> i : cls.getInterfaces()) {
if (interfacesFound.add(i)) {
getAllInterfaces(i, interfacesFound);
}
}
-
cls = cls.getSuperclass();
- }
- }
+ }
+ }
- // Convert list
- // ----------------------------------------------------------------------
/**
- *
Given a {@code List} of class names, this method converts them into classes.
+ * Gets a {@link List} of superclasses for the given class.
*
- *
A new {@code List} is returned. If the class name cannot be found, {@code null}
- * is stored in the {@code List}. If the class name in the {@code List} is
- * {@code null}, {@code null} is stored in the output {@code List}.
+ *
+ *
The first entry is the superclass of the given class.
+ *
The last entry is {@link Object}'s class.
+ *
*
- * @param classNames the classNames to change
- * @return a {@code List} of Class objects corresponding to the class names,
- * {@code null} if null input
- * @throws ClassCastException if classNames contains a non String entry
+ * @param cls The class to look up, may be {@code null}.
+ * @return The {@link List} of superclasses in order going up from this one {@code null} if null input.
*/
- public static List> convertClassNamesToClasses(final List classNames) {
- if (classNames == null) {
+ public static List> getAllSuperclasses(final Class> cls) {
+ if (cls == null) {
return null;
}
- final List> classes = new ArrayList<>(classNames.size());
- for (final String className : classNames) {
- try {
- classes.add(Class.forName(className));
- } catch (final Exception ex) {
- classes.add(null);
- }
+ final List> classes = new ArrayList<>();
+ Class> superclass = cls.getSuperclass();
+ while (superclass != null) {
+ classes.add(superclass);
+ superclass = superclass.getSuperclass();
}
return classes;
}
/**
- *
Given a {@code List} of {@code Class} objects, this method converts
- * them into class names.
- *
- *
A new {@code List} is returned. {@code null} objects will be copied into
- * the returned list as {@code null}.
+ * Gets the canonical class name for a {@link Class}.
*
- * @param classes the classes to change
- * @return a {@code List} of class names corresponding to the Class objects,
- * {@code null} if null input
- * @throws ClassCastException if {@code classes} contains a non-{@code Class} entry
+ * @param cls The class for which to get the canonical class name; may be null.
+ * @return The canonical name of the class, or the empty String.
+ * @since 3.7
+ * @see Class#getCanonicalName()
*/
- public static List convertClassesToClassNames(final List> classes) {
- if (classes == null) {
- return null;
- }
- final List classNames = new ArrayList<>(classes.size());
- for (final Class> cls : classes) {
- if (cls == null) {
- classNames.add(null);
- } else {
- classNames.add(cls.getName());
- }
- }
- return classNames;
+ public static String getCanonicalName(final Class> cls) {
+ return getCanonicalName(cls, StringUtils.EMPTY);
}
- // Is assignable
- // ----------------------------------------------------------------------
/**
- *
Checks if an array of Classes can be assigned to another array of Classes.
- *
- *
This method calls {@link #isAssignable(Class, Class) isAssignable} for each
- * Class pair in the input arrays. It can be used to check if a set of arguments
- * (the first parameter) are suitably compatible with a set of method parameter types
- * (the second parameter).
- *
- *
Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, this
- * method takes into account widenings of primitive classes and
- * {@code null}s.
- *
- *
Primitive widenings allow an int to be assigned to a {@code long},
- * {@code float} or {@code double}. This method returns the correct
- * result for these cases.
- *
- *
{@code Null} may be assigned to any reference type. This method will
- * return {@code true} if {@code null} is passed in and the toClass is
- * non-primitive.
- *
- *
Specifically, this method tests whether the type represented by the
- * specified {@code Class} parameter can be converted to the type
- * represented by this {@code Class} object via an identity conversion
- * widening primitive or widening reference conversion. See
- * The Java Language Specification,
- * sections 5.1.1, 5.1.2 and 5.1.4 for details.
+ * Gets the canonical name for a {@link Class}.
*
- *
Since Lang 3.0, this method will default behavior for
- * calculating assignability between primitive and wrapper types corresponding
- * to the running Java version; i.e. autoboxing will be the default
- * behavior in VMs running Java versions > 1.5.
- *
- * @param classArray the array of Classes to check, may be {@code null}
- * @param toClassArray the array of Classes to try to assign into, may be {@code null}
- * @return {@code true} if assignment possible
+ * @param cls The class for which to get the canonical class name; may be null.
+ * @param valueIfNull The return value if null.
+ * @return The canonical name of the class, or {@code valueIfNull}.
+ * @since 3.7
+ * @see Class#getCanonicalName()
*/
- public static boolean isAssignable(final Class>[] classArray, final Class>... toClassArray) {
- return isAssignable(classArray, toClassArray, true);
+ public static String getCanonicalName(final Class> cls, final String valueIfNull) {
+ if (cls == null) {
+ return valueIfNull;
+ }
+ final String canonicalName = cls.getCanonicalName();
+ return canonicalName == null ? valueIfNull : canonicalName;
}
/**
- *
Checks if an array of Classes can be assigned to another array of Classes.
+ * Gets the canonical name for an {@link Object}.
*
- *
This method calls {@link #isAssignable(Class, Class) isAssignable} for each
- * Class pair in the input arrays. It can be used to check if a set of arguments
- * (the first parameter) are suitably compatible with a set of method parameter types
- * (the second parameter).
- *
- *
Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, this
- * method takes into account widenings of primitive classes and
- * {@code null}s.
+ * @param object The object for which to get the canonical class name; may be null.
+ * @return The canonical name of the object, or the empty String.
+ * @since 3.7
+ * @see Class#getCanonicalName()
+ */
+ public static String getCanonicalName(final Object object) {
+ return getCanonicalName(object, StringUtils.EMPTY);
+ }
+
+ /**
+ * Gets the canonical name for an {@link Object}.
*
- *
Primitive widenings allow an int to be assigned to a {@code long},
- * {@code float} or {@code double}. This method returns the correct
- * result for these cases.
+ * @param object The object for which to get the canonical class name; may be null.
+ * @param valueIfNull The return value if null.
+ * @return The canonical name of the object or {@code valueIfNull}.
+ * @since 3.7
+ * @see Class#getCanonicalName()
+ */
+ public static String getCanonicalName(final Object object, final String valueIfNull) {
+ if (object == null) {
+ return valueIfNull;
+ }
+ final String canonicalName = object.getClass().getCanonicalName();
+ return canonicalName == null ? valueIfNull : canonicalName;
+ }
+
+ /**
+ * Converts a given name of class into canonical format. If name of class is not a name of array class it returns
+ * unchanged name.
*
- *
{@code Null} may be assigned to any reference type. This method will
- * return {@code true} if {@code null} is passed in and the toClass is
- * non-primitive.
+ *
+ * The method does not change the {@code $} separators in case the class is inner class.
+ *
*
- *
Specifically, this method tests whether the type represented by the
- * specified {@code Class} parameter can be converted to the type
- * represented by this {@code Class} object via an identity conversion
- * widening primitive or widening reference conversion. See
- * The Java Language Specification,
- * sections 5.1.1, 5.1.2 and 5.1.4 for details.
+ *
*
- * @param classArray the array of Classes to check, may be {@code null}
- * @param toClassArray the array of Classes to try to assign into, may be {@code null}
- * @param autoboxing whether to use implicit autoboxing/unboxing between primitives and wrappers
- * @return {@code true} if assignment possible
+ * @param name The name of class.
+ * @return canonical form of class name.
+ * @throws IllegalArgumentException if the class name is invalid.
*/
- public static boolean isAssignable(Class>[] classArray, Class>[] toClassArray, final boolean autoboxing) {
- if (!ArrayUtils.isSameLength(classArray, toClassArray)) {
- return false;
+ private static String getCanonicalName(final String name) {
+ String className = StringUtils.deleteWhitespace(name);
+ if (className == null) {
+ return null;
+ }
+ int dim = 0;
+ final int len = className.length();
+ while (dim < len && className.charAt(dim) == '[') {
+ dim++;
+ if (dim > MAX_DIMENSIONS) {
+ throw new IllegalArgumentException(String.format("Maximum array dimension %d exceeded", MAX_DIMENSIONS));
+ }
}
- if (classArray == null) {
- classArray = ArrayUtils.EMPTY_CLASS_ARRAY;
+ if (dim >= len) {
+ throw new IllegalArgumentException(String.format("Invalid class name %s", name));
}
- if (toClassArray == null) {
- toClassArray = ArrayUtils.EMPTY_CLASS_ARRAY;
+ if (dim < 1) {
+ return className;
}
- for (int i = 0; i < classArray.length; i++) {
- if (!isAssignable(classArray[i], toClassArray[i], autoboxing)) {
- return false;
+ className = className.substring(dim);
+ if (className.startsWith("L")) {
+ if (!className.endsWith(";") || className.length() < 3) {
+ throw new IllegalArgumentException(String.format("Invalid class name %s", name));
}
+ className = className.substring(1, className.length() - 1);
+ } else if (className.length() == 1) {
+ final String primitive = REVERSE_ABBREVIATION_MAP.get(className.substring(0, 1));
+ if (primitive == null) {
+ throw new IllegalArgumentException(String.format("Invalid class name %s", name));
+ }
+ className = primitive;
+ } else {
+ throw new IllegalArgumentException(String.format("Invalid class name %s", name));
}
- return true;
- }
-
- /**
- * Returns whether the given {@code type} is a primitive or primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character},
- * {@link Short}, {@link Integer}, {@link Long}, {@link Double}, {@link Float}).
- *
- * @param type
- * The class to query or null.
- * @return true if the given {@code type} is a primitive or primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character},
- * {@link Short}, {@link Integer}, {@link Long}, {@link Double}, {@link Float}).
- * @since 3.1
- */
- public static boolean isPrimitiveOrWrapper(final Class> type) {
- if (type == null) {
- return false;
+ final StringBuilder canonicalClassNameBuffer = new StringBuilder(className.length() + dim * 2);
+ canonicalClassNameBuffer.append(className);
+ for (int i = 0; i < dim; i++) {
+ canonicalClassNameBuffer.append("[]");
}
- return type.isPrimitive() || isPrimitiveWrapper(type);
+ return canonicalClassNameBuffer.toString();
}
/**
- * Returns whether the given {@code type} is a primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character}, {@link Short},
- * {@link Integer}, {@link Long}, {@link Double}, {@link Float}).
+ * Gets the (initialized) class represented by {@code className} using the {@code classLoader}. This implementation
+ * supports the syntaxes "{@code java.util.Map.Entry[]}", "{@code java.util.Map$Entry[]}",
+ * "{@code [Ljava.util.Map.Entry;}", and "{@code [Ljava.util.Map$Entry;}".
+ *
+ * The provided class name is normalized by removing all whitespace. This is especially helpful when handling XML element values in which whitespace has not
+ * been collapsed.
+ *
+ *
+ * Security note: because all whitespace is deleted before the class is resolved (and a failing {@code '.'} may be retried as {@code '$'}
+ * for inner classes), many distinct input strings resolve to the same class, while {@link Class#forName(String)} performs no such normalization. Validating
+ * an untrusted class name by string comparison before calling this method is therefore unsound: for example, {@code " java.lang.Runtime"} fails a
+ * naive {@code startsWith("java.")} denylist check on the raw string, yet loads {@code java.lang.Runtime}. Validate the class name after
+ * normalization, validate the resolved {@link Class} object itself, or use {@link #getClassStrict(ClassLoader, String, boolean)} which performs no
+ * whitespace normalization.
+ *
*
- * @param type
- * The class to query or null.
- * @return true if the given {@code type} is a primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character}, {@link Short},
- * {@link Integer}, {@link Long}, {@link Double}, {@link Float}).
- * @since 3.1
+ * @param classLoader The class loader to use to load the class.
+ * @param className The class name.
+ * @return The class represented by {@code className} using the {@code classLoader}.
+ * @throws NullPointerException if the className is null.
+ * @throws ClassNotFoundException if the class is not found.
+ * @throws IllegalArgumentException Thrown if the class name represents an array with more dimensions than the JVM supports, 255.
+ * @throws IllegalArgumentException Thrown if the class name length is greater than 65,535.
+ * @see Class#forName(String, boolean, ClassLoader)
+ * @see JVM: Array dimension limits in JVM Specification CONSTANT_Class_info
+ * @see JLS: Fully Qualified Names and Canonical Names
+ * @see JLS: The Form of a Binary
*/
- public static boolean isPrimitiveWrapper(final Class> type) {
- return wrapperPrimitiveMap.containsKey(type);
+ public static Class> getClass(final ClassLoader classLoader, final String className) throws ClassNotFoundException {
+ return getClass(classLoader, className, true);
}
/**
- *
Checks if one {@code Class} can be assigned to a variable of
- * another {@code Class}.
- *
- *
Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method,
- * this method takes into account widenings of primitive classes and
- * {@code null}s.
- *
- *
Primitive widenings allow an int to be assigned to a long, float or
- * double. This method returns the correct result for these cases.
- *
- *
{@code Null} may be assigned to any reference type. This method
- * will return {@code true} if {@code null} is passed in and the
- * toClass is non-primitive.
- *
- *
Specifically, this method tests whether the type represented by the
- * specified {@code Class} parameter can be converted to the type
- * represented by this {@code Class} object via an identity conversion
- * widening primitive or widening reference conversion. See
- * The Java Language Specification,
- * sections 5.1.1, 5.1.2 and 5.1.4 for details.
- *
- *
Since Lang 3.0, this method will default behavior for
- * calculating assignability between primitive and wrapper types corresponding
- * to the running Java version; i.e. autoboxing will be the default
- * behavior in VMs running Java versions > 1.5.
+ * Gets the class represented by {@code className} using the {@code classLoader}. This implementation supports the
+ * syntaxes "{@code java.util.Map.Entry[]}", "{@code java.util.Map$Entry[]}", "{@code [Ljava.util.Map.Entry;}", and
+ * "{@code [Ljava.util.Map$Entry;}".
+ *
+ * The provided class name is normalized by removing all whitespace. This is especially helpful when handling XML element values in which whitespace has not
+ * been collapsed.
+ *
+ *
+ * Security note: because all whitespace is deleted before the class is resolved (and a failing {@code '.'} may be retried as {@code '$'}
+ * for inner classes), many distinct input strings resolve to the same class, while {@link Class#forName(String)} performs no such normalization. Validating
+ * an untrusted class name by string comparison before calling this method is therefore unsound: for example, {@code " java.lang.Runtime"} fails a
+ * naive {@code startsWith("java.")} denylist check on the raw string, yet loads {@code java.lang.Runtime}. Validate the class name after
+ * normalization, validate the resolved {@link Class} object itself, or use {@link #getClassStrict(ClassLoader, String, boolean)} which performs no
+ * whitespace normalization.
+ *
*
- * @param cls the Class to check, may be null
- * @param toClass the Class to try to assign into, returns false if null
- * @return {@code true} if assignment possible
- */
- public static boolean isAssignable(final Class> cls, final Class> toClass) {
- return isAssignable(cls, toClass, true);
+ * @param classLoader The class loader to use to load the class.
+ * @param className The class name.
+ * @param initialize whether the class must be initialized.
+ * @return The class represented by {@code className} using the {@code classLoader}.
+ * @throws NullPointerException if the className is null.
+ * @throws ClassNotFoundException if the class is not found.
+ * @throws IllegalArgumentException Thrown if the class name represents an array with more dimensions than the JVM supports, 255.
+ * @throws IllegalArgumentException Thrown if the class name length is greater than 65,535.
+ * @see Class#forName(String, boolean, ClassLoader)
+ * @see JVM: Array dimension limits in JVM Specification CONSTANT_Class_info
+ * @see JLS: Fully Qualified Names and Canonical Names
+ * @see JLS: The Form of a Binary
+ */
+ public static Class> getClass(final ClassLoader classLoader, final String className, final boolean initialize) throws ClassNotFoundException {
+ return getClass(classLoader, className, initialize, true);
}
/**
- *
Checks if one {@code Class} can be assigned to a variable of
- * another {@code Class}.
- *
- *
Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method,
- * this method takes into account widenings of primitive classes and
- * {@code null}s.
- *
- *
Primitive widenings allow an int to be assigned to a long, float or
- * double. This method returns the correct result for these cases.
{@code Null} may be assigned to any reference type. This method
- * will return {@code true} if {@code null} is passed in and the
- * toClass is non-primitive.
- *
- *
Specifically, this method tests whether the type represented by the
- * specified {@code Class} parameter can be converted to the type
- * represented by this {@code Class} object via an identity conversion
- * widening primitive or widening reference conversion. See
- * The Java Language Specification,
- * sections 5.1.1, 5.1.2 and 5.1.4 for details.
- *
- * @param cls the Class to check, may be null
- * @param toClass the Class to try to assign into, returns false if null
- * @param autoboxing whether to use implicit autoboxing/unboxing between primitives and wrappers
- * @return {@code true} if assignment possible
+ * @param classLoader The class loader to use to load the class.
+ * @param className The class name.
+ * @param initialize whether the class must be initialized.
+ * @param normalizeWhitespace whether to delete all whitespace from the class name before resolving it.
+ * @return The class represented by {@code className} using the {@code classLoader}.
+ * @throws NullPointerException if the className is null.
+ * @throws ClassNotFoundException if the class is not found.
*/
- public static boolean isAssignable(Class> cls, final Class> toClass, final boolean autoboxing) {
- if (toClass == null) {
- return false;
- }
- // have to check for null, as isAssignableFrom doesn't
- if (cls == null) {
- return !toClass.isPrimitive();
- }
- //autoboxing:
- if (autoboxing) {
- if (cls.isPrimitive() && !toClass.isPrimitive()) {
- cls = primitiveToWrapper(cls);
- if (cls == null) {
- return false;
- }
- }
- if (toClass.isPrimitive() && !cls.isPrimitive()) {
- cls = wrapperToPrimitive(cls);
- if (cls == null) {
- return false;
+ private static Class> getClass(final ClassLoader classLoader, final String className, final boolean initialize, final boolean normalizeWhitespace)
+ throws ClassNotFoundException {
+ // This method was re-written to avoid recursion and stack overflows found by fuzz testing.
+ String next = className;
+ int lastDotIndex = -1;
+ do {
+ try {
+ final Class> clazz = getPrimitiveClass(next);
+ return clazz != null ? clazz : Class.forName(normalizeWhitespace ? toCleanName(next) : toEncodedName(next), initialize, classLoader);
+ } catch (final ClassNotFoundException ex) {
+ lastDotIndex = next.lastIndexOf(PACKAGE_SEPARATOR_CHAR);
+ if (lastDotIndex != -1) {
+ next = next.substring(0, lastDotIndex) + INNER_CLASS_SEPARATOR_CHAR + next.substring(lastDotIndex + 1);
}
}
- }
- if (cls.equals(toClass)) {
- return true;
- }
- if (cls.isPrimitive()) {
- if (!toClass.isPrimitive()) {
- return false;
- }
- if (Integer.TYPE.equals(cls)) {
- return Long.TYPE.equals(toClass)
- || Float.TYPE.equals(toClass)
- || Double.TYPE.equals(toClass);
- }
- if (Long.TYPE.equals(cls)) {
- return Float.TYPE.equals(toClass)
- || Double.TYPE.equals(toClass);
- }
- if (Boolean.TYPE.equals(cls)) {
- return false;
- }
- if (Double.TYPE.equals(cls)) {
- return false;
- }
- if (Float.TYPE.equals(cls)) {
- return Double.TYPE.equals(toClass);
- }
- if (Character.TYPE.equals(cls)) {
- return Integer.TYPE.equals(toClass)
- || Long.TYPE.equals(toClass)
- || Float.TYPE.equals(toClass)
- || Double.TYPE.equals(toClass);
- }
- if (Short.TYPE.equals(cls)) {
- return Integer.TYPE.equals(toClass)
- || Long.TYPE.equals(toClass)
- || Float.TYPE.equals(toClass)
- || Double.TYPE.equals(toClass);
- }
- if (Byte.TYPE.equals(cls)) {
- return Short.TYPE.equals(toClass)
- || Integer.TYPE.equals(toClass)
- || Long.TYPE.equals(toClass)
- || Float.TYPE.equals(toClass)
- || Double.TYPE.equals(toClass);
- }
- // should never get here
- return false;
- }
- return toClass.isAssignableFrom(cls);
+ } while (lastDotIndex != -1);
+ throw new ClassNotFoundException(className);
}
/**
- *
Converts the specified primitive Class object to its corresponding
- * wrapper Class object.
- *
- *
NOTE: From v2.2, this method handles {@code Void.TYPE},
- * returning {@code Void.TYPE}.
+ * Gets the (initialized) class represented by {@code className} using the current thread's context class loader.
+ * This implementation supports the syntaxes "{@code java.util.Map.Entry[]}", "{@code java.util.Map$Entry[]}",
+ * "{@code [Ljava.util.Map.Entry;}", and "{@code [Ljava.util.Map$Entry;}".
+ *
+ * The provided class name is normalized by removing all whitespace. This is especially helpful when handling XML element values in which whitespace has not
+ * been collapsed.
+ *
+ *
+ * Security note: because all whitespace is deleted before the class is resolved (and a failing {@code '.'} may be retried as {@code '$'}
+ * for inner classes), many distinct input strings resolve to the same class, while {@link Class#forName(String)} performs no such normalization. Validating
+ * an untrusted class name by string comparison before calling this method is therefore unsound: for example, {@code " java.lang.Runtime"} fails a
+ * naive {@code startsWith("java.")} denylist check on the raw string, yet loads {@code java.lang.Runtime}. Validate the class name after
+ * normalization, validate the resolved {@link Class} object itself, or use {@link #getClassStrict(ClassLoader, String, boolean)} which performs no
+ * whitespace normalization.
+ *
*
- * @param cls the class to convert, may be null
- * @return the wrapper class for {@code cls} or {@code cls} if
- * {@code cls} is not a primitive. {@code null} if null input.
- * @since 2.1
+ * @param className The class name
+ * @return The class represented by {@code className} using the current thread's context class loader
+ * @throws NullPointerException if the className is null
+ * @throws ClassNotFoundException if the class is not found
+ * @throws IllegalArgumentException Thrown if the class name represents an array with more dimensions than the JVM supports, 255.
+ * @throws IllegalArgumentException Thrown if the class name length is greater than 65,535.
+ * @see Class#forName(String, boolean, ClassLoader)
+ * @see JVM: Array dimension limits in JVM Specification CONSTANT_Class_info
+ * @see JLS: Fully Qualified Names and Canonical Names
+ * @see JLS: The Form of a Binary
*/
- public static Class> primitiveToWrapper(final Class> cls) {
- Class> convertedClass = cls;
- if (cls != null && cls.isPrimitive()) {
- convertedClass = primitiveWrapperMap.get(cls);
- }
- return convertedClass;
+ public static Class> getClass(final String className) throws ClassNotFoundException {
+ return getClass(className, true);
}
/**
- *
Converts the specified array of primitive Class objects to an array of
- * its corresponding wrapper Class objects.
+ * Gets the class represented by {@code className} using the current thread's context class loader. This
+ * implementation supports the syntaxes "{@code java.util.Map.Entry[]}", "{@code java.util.Map$Entry[]}",
+ * "{@code [Ljava.util.Map.Entry;}", and "{@code [Ljava.util.Map$Entry;}".
+ *
+ * The provided class name is normalized by removing all whitespace. This is especially helpful when handling XML element values in which whitespace has not
+ * been collapsed.
+ *
+ *
+ * Security note: because all whitespace is deleted before the class is resolved (and a failing {@code '.'} may be retried as {@code '$'}
+ * for inner classes), many distinct input strings resolve to the same class, while {@link Class#forName(String)} performs no such normalization. Validating
+ * an untrusted class name by string comparison before calling this method is therefore unsound: for example, {@code " java.lang.Runtime"} fails a
+ * naive {@code startsWith("java.")} denylist check on the raw string, yet loads {@code java.lang.Runtime}. Validate the class name after
+ * normalization, validate the resolved {@link Class} object itself, or use {@link #getClassStrict(ClassLoader, String, boolean)} which performs no
+ * whitespace normalization.
+ *
*
- * @param classes the class array to convert, may be null or empty
- * @return an array which contains for each given class, the wrapper class or
- * the original class if class is not a primitive. {@code null} if null input.
- * Empty array if an empty array passed in.
- * @since 2.1
+ * @param className The class name.
+ * @param initialize whether the class must be initialized.
+ * @return The class represented by {@code className} using the current thread's context class loader.
+ * @throws NullPointerException if the className is null.
+ * @throws ClassNotFoundException if the class is not found.
+ * @throws IllegalArgumentException Thrown if the class name represents an array with more dimensions than the JVM supports, 255.
+ * @throws IllegalArgumentException Thrown if the class name length is greater than 65,535.
+ * @see Class#forName(String, boolean, ClassLoader)
+ * @see JVM: Array dimension limits in JVM Specification CONSTANT_Class_info
+ * @see JLS: Fully Qualified Names and Canonical Names
+ * @see JLS: The Form of a Binary
*/
- public static Class>[] primitivesToWrappers(final Class>... classes) {
- if (classes == null) {
- return null;
- }
-
- if (classes.length == 0) {
- return classes;
- }
-
- final Class>[] convertedClasses = new Class[classes.length];
- for (int i = 0; i < classes.length; i++) {
- convertedClasses[i] = primitiveToWrapper(classes[i]);
- }
- return convertedClasses;
+ public static Class> getClass(final String className, final boolean initialize) throws ClassNotFoundException {
+ final ClassLoader contextCL = Thread.currentThread().getContextClassLoader();
+ final ClassLoader loader = contextCL == null ? ClassUtils.class.getClassLoader() : contextCL;
+ return getClass(loader, className, initialize);
}
/**
- *
Converts the specified wrapper class to its corresponding primitive
- * class.
- *
- *
This method is the counter part of {@code primitiveToWrapper()}.
- * If the passed in class is a wrapper class for a primitive type, this
- * primitive type will be returned (e.g. {@code Integer.TYPE} for
- * {@code Integer.class}). For other classes, or if the parameter is
- * null, the return value is null.
+ * Gets the class represented by {@code className} using the {@code classLoader}, without normalizing the class name.
+ *
+ * Unlike {@link #getClass(ClassLoader, String, boolean)}, this method does not delete whitespace from the class name: a name that differs from
+ * the intended binary name only by whitespace throws {@link ClassNotFoundException}, matching {@link Class#forName(String, boolean, ClassLoader)}. Use
+ * this variant when the class name may come from an untrusted source, so that host-side string validation of the raw name cannot be bypassed through
+ * whitespace the loader would otherwise silently remove.
+ *
+ *
+ * The syntaxes "{@code java.util.Map.Entry[]}", "{@code java.util.Map$Entry[]}", "{@code [Ljava.util.Map.Entry;}", and "{@code [Ljava.util.Map$Entry;}"
+ * are still supported: a failing {@code '.'} is retried as {@code '$'} to find inner classes, so more than one dotted spelling can still resolve to the
+ * same inner class. When validating untrusted names, prefer validating the resolved {@link Class} object.
+ *
*
- * @param cls the class to convert, may be null
- * @return the corresponding primitive type if {@code cls} is a
- * wrapper class, null otherwise
- * @see #primitiveToWrapper(Class)
- * @since 2.4
- */
- public static Class> wrapperToPrimitive(final Class> cls) {
- return wrapperPrimitiveMap.get(cls);
+ * @param classLoader The class loader to use to load the class.
+ * @param className The class name.
+ * @param initialize whether the class must be initialized.
+ * @return The class represented by {@code className} using the {@code classLoader}.
+ * @throws NullPointerException if the className is null.
+ * @throws ClassNotFoundException if the class is not found.
+ * @throws IllegalArgumentException Thrown if the class name represents an array with more dimensions than the JVM supports, 255.
+ * @throws IllegalArgumentException Thrown if the class name length is greater than 65,535.
+ * @see Class#forName(String, boolean, ClassLoader)
+ * @see #getClass(ClassLoader, String, boolean)
+ * @since 3.21.0
+ */
+ public static Class> getClassStrict(final ClassLoader classLoader, final String className, final boolean initialize) throws ClassNotFoundException {
+ return getClass(classLoader, className, initialize, false);
}
/**
- *
Converts the specified array of wrapper Class objects to an array of
- * its corresponding primitive Class objects.
+ * Gets the (initialized) class represented by {@code className} using the current thread's context class loader, without normalizing the class name.
+ *
+ * Unlike {@link #getClass(String)}, this method does not delete whitespace from the class name: a name that differs from the intended binary
+ * name only by whitespace throws {@link ClassNotFoundException}, matching {@link Class#forName(String)}. Use this variant when the class name may come
+ * from an untrusted source, so that host-side string validation of the raw name cannot be bypassed through whitespace the loader would otherwise silently
+ * remove.
+ *
+ *
+ * The syntaxes "{@code java.util.Map.Entry[]}", "{@code java.util.Map$Entry[]}", "{@code [Ljava.util.Map.Entry;}", and "{@code [Ljava.util.Map$Entry;}"
+ * are still supported: a failing {@code '.'} is retried as {@code '$'} to find inner classes, so more than one dotted spelling can still resolve to the
+ * same inner class. When validating untrusted names, prefer validating the resolved {@link Class} object.
+ *
*
- *
This method invokes {@code wrapperToPrimitive()} for each element
- * of the passed in array.
+ * @param className The class name.
+ * @return The class represented by {@code className} using the current thread's context class loader.
+ * @throws NullPointerException if the className is null.
+ * @throws ClassNotFoundException if the class is not found.
+ * @throws IllegalArgumentException Thrown if the class name represents an array with more dimensions than the JVM supports, 255.
+ * @throws IllegalArgumentException Thrown if the class name length is greater than 65,535.
+ * @see Class#forName(String)
+ * @see #getClass(String)
+ * @since 3.21.0
+ */
+ public static Class> getClassStrict(final String className) throws ClassNotFoundException {
+ final ClassLoader contextCL = Thread.currentThread().getContextClassLoader();
+ final ClassLoader loader = contextCL == null ? ClassUtils.class.getClassLoader() : contextCL;
+ return getClassStrict(loader, className, true);
+ }
+
+ /**
+ * Delegates to {@link Class#getComponentType()} using generics.
*
- * @param classes the class array to convert, may be null or empty
- * @return an array which contains for each given class, the primitive class or
- * null if the original class is not a wrapper class. {@code null} if null input.
- * Empty array if an empty array passed in.
- * @see #wrapperToPrimitive(Class)
- * @since 2.4
+ * @param The array class type.
+ * @param cls A class or null.
+ * @return The array component type or null.
+ * @see Class#getComponentType()
+ * @since 3.13.0
*/
- public static Class>[] wrappersToPrimitives(final Class>... classes) {
- if (classes == null) {
- return null;
- }
-
- if (classes.length == 0) {
- return classes;
- }
-
- final Class>[] convertedClasses = new Class[classes.length];
- for (int i = 0; i < classes.length; i++) {
- convertedClasses[i] = wrapperToPrimitive(classes[i]);
- }
- return convertedClasses;
+ @SuppressWarnings("unchecked")
+ public static Class getComponentType(final Class cls) {
+ return cls == null ? null : (Class) cls.getComponentType();
}
- // Inner class
- // ----------------------------------------------------------------------
/**
- *
Is the specified class an inner class or static nested class.
+ * Null-safe version of {@code cls.getName()}
*
- * @param cls the class to check, may be null
- * @return {@code true} if the class is an inner or static nested class,
- * false if not or {@code null}
+ * @param cls The class for which to get the class name; may be null.
+ * @return The class name or the empty string in case the argument is {@code null}.
+ * @since 3.7
+ * @see Class#getSimpleName()
*/
- public static boolean isInnerClass(final Class> cls) {
- return cls != null && cls.getEnclosingClass() != null;
+ public static String getName(final Class> cls) {
+ return getName(cls, StringUtils.EMPTY);
}
- // Class loading
- // ----------------------------------------------------------------------
/**
- * Returns the class represented by {@code className} using the
- * {@code classLoader}. This implementation supports the syntaxes
- * "{@code java.util.Map.Entry[]}", "{@code java.util.Map$Entry[]}",
- * "{@code [Ljava.util.Map.Entry;}", and "{@code [Ljava.util.Map$Entry;}".
+ * Null-safe version of {@code cls.getName()}
*
- * @param classLoader the class loader to use to load the class
- * @param className the class name
- * @param initialize whether the class must be initialized
- * @return the class represented by {@code className} using the {@code classLoader}
- * @throws ClassNotFoundException if the class is not found
+ * @param cls The class for which to get the class name; may be null.
+ * @param valueIfNull The return value if the argument {@code cls} is {@code null}.
+ * @return The class name or {@code valueIfNull}
+ * @since 3.7
+ * @see Class#getName()
*/
- public static Class> getClass(
- final ClassLoader classLoader, final String className, final boolean initialize) throws ClassNotFoundException {
- try {
- Class> clazz;
- if (namePrimitiveMap.containsKey(className)) {
- clazz = namePrimitiveMap.get(className);
- } else {
- clazz = Class.forName(toCanonicalName(className), initialize, classLoader);
- }
- return clazz;
- } catch (final ClassNotFoundException ex) {
- // allow path separators (.) as inner class name separators
- final int lastDotIndex = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR);
-
- if (lastDotIndex != -1) {
- try {
- return getClass(classLoader, className.substring(0, lastDotIndex) +
- INNER_CLASS_SEPARATOR_CHAR + className.substring(lastDotIndex + 1),
- initialize);
- } catch (final ClassNotFoundException ex2) { // NOPMD
- // ignore exception
- }
- }
+ public static String getName(final Class> cls, final String valueIfNull) {
+ return getName(cls, valueIfNull, false);
+ }
- throw ex;
- }
+ static String getName(final Class> cls, final String valueIfNull, final boolean simple) {
+ return cls == null ? valueIfNull : simple ? cls.getSimpleName() : cls.getName();
}
/**
- * Returns the (initialized) class represented by {@code className}
- * using the {@code classLoader}. This implementation supports
- * the syntaxes "{@code java.util.Map.Entry[]}",
- * "{@code java.util.Map$Entry[]}", "{@code [Ljava.util.Map.Entry;}",
- * and "{@code [Ljava.util.Map$Entry;}".
+ * Null-safe version of {@code object.getClass().getName()}
*
- * @param classLoader the class loader to use to load the class
- * @param className the class name
- * @return the class represented by {@code className} using the {@code classLoader}
- * @throws ClassNotFoundException if the class is not found
+ * @param object The object for which to get the class name; may be null.
+ * @return The class name or the empty String.
+ * @since 3.7
+ * @see Class#getSimpleName()
*/
- public static Class> getClass(final ClassLoader classLoader, final String className) throws ClassNotFoundException {
- return getClass(classLoader, className, true);
+ public static String getName(final Object object) {
+ return getName(object, StringUtils.EMPTY);
}
/**
- * Returns the (initialized) class represented by {@code className}
- * using the current thread's context class loader. This implementation
- * supports the syntaxes "{@code java.util.Map.Entry[]}",
- * "{@code java.util.Map$Entry[]}", "{@code [Ljava.util.Map.Entry;}",
- * and "{@code [Ljava.util.Map$Entry;}".
+ * Null-safe version of {@code object.getClass().getSimpleName()}
*
- * @param className the class name
- * @return the class represented by {@code className} using the current thread's context class loader
- * @throws ClassNotFoundException if the class is not found
+ * @param object The object for which to get the class name; may be null.
+ * @param valueIfNull The value to return if {@code object} is {@code null}.
+ * @return The class name or {@code valueIfNull}.
+ * @since 3.0
+ * @see Class#getName()
*/
- public static Class> getClass(final String className) throws ClassNotFoundException {
- return getClass(className, true);
+ public static String getName(final Object object, final String valueIfNull) {
+ return object == null ? valueIfNull : object.getClass().getName();
}
/**
- * Returns the class represented by {@code className} using the
- * current thread's context class loader. This implementation supports the
- * syntaxes "{@code java.util.Map.Entry[]}", "{@code java.util.Map$Entry[]}",
- * "{@code [Ljava.util.Map.Entry;}", and "{@code [Ljava.util.Map$Entry;}".
+ * Gets the package name from the canonical name of a {@link Class}.
*
- * @param className the class name
- * @param initialize whether the class must be initialized
- * @return the class represented by {@code className} using the current thread's context class loader
- * @throws ClassNotFoundException if the class is not found
+ * @param cls The class to get the package name for, may be {@code null}.
+ * @return The package name or an empty string.
+ * @since 2.4
*/
- public static Class> getClass(final String className, final boolean initialize) throws ClassNotFoundException {
- final ClassLoader contextCL = Thread.currentThread().getContextClassLoader();
- final ClassLoader loader = contextCL == null ? ClassUtils.class.getClassLoader() : contextCL;
- return getClass(loader, className, initialize);
+ public static String getPackageCanonicalName(final Class> cls) {
+ if (cls == null) {
+ return StringUtils.EMPTY;
+ }
+ return getPackageCanonicalName(cls.getName());
}
- // Public method
- // ----------------------------------------------------------------------
/**
- *
Returns the desired Method much like {@code Class.getMethod}, however
- * it ensures that the returned Method is from a public class or interface and not
- * from an anonymous inner class. This means that the Method is invokable and
- * doesn't fall foul of Java bug
- * 4071957).
+ * Gets the package name from the class name of an {@link Object}.
*
- *
- * Set set = Collections.unmodifiableSet(...);
- * Method method = ClassUtils.getPublicMethod(set.getClass(), "isEmpty", new Class[0]);
- * Object result = method.invoke(set, new Object[]);
- *
+ * @param object The class to get the package name for, may be null.
+ * @param valueIfNull The value to return if null.
+ * @return The package name of the object, or the null value.
+ * @since 2.4
+ */
+ public static String getPackageCanonicalName(final Object object, final String valueIfNull) {
+ if (object == null) {
+ return valueIfNull;
+ }
+ return getPackageCanonicalName(object.getClass().getName());
+ }
+
+ /**
+ * Gets the package name from the class name.
+ *
+ *
+ * The string passed in is assumed to be a class name - it is not checked.
+ *
+ *
+ * If the class is in the default package, return an empty string.
+ *
+ *
+ * @param name The name to get the package name for, may be {@code null}.
+ * @return The package name or an empty string.
+ * @since 2.4
+ */
+ public static String getPackageCanonicalName(final String name) {
+ return getPackageName(getCanonicalName(name));
+ }
+
+ /**
+ * Gets the package name of a {@link Class}.
+ *
+ * @param cls The class to get the package name for, may be {@code null}.
+ * @return The package name or an empty string
+ */
+ public static String getPackageName(final Class> cls) {
+ if (cls == null) {
+ return StringUtils.EMPTY;
+ }
+ return getPackageName(cls.getName());
+ }
+
+ /**
+ * Gets the package name of an {@link Object}.
*
- * @param cls the class to check, not null
- * @param methodName the name of the method
- * @param parameterTypes the list of parameters
- * @return the method
- * @throws NullPointerException if the class is null
- * @throws SecurityException if a security violation occurred
- * @throws NoSuchMethodException if the method is not found in the given class
- * or if the method doesn't conform with the requirements
+ * @param object The class to get the package name for, may be null.
+ * @param valueIfNull The value to return if null.
+ * @return The package name of the object, or the null value.
*/
- public static Method getPublicMethod(final Class> cls, final String methodName, final Class>... parameterTypes)
- throws NoSuchMethodException {
+ public static String getPackageName(final Object object, final String valueIfNull) {
+ if (object == null) {
+ return valueIfNull;
+ }
+ return getPackageName(object.getClass());
+ }
+ /**
+ * Gets the package name from a {@link String}.
+ *
+ *
+ * The string passed in is assumed to be a class name.
+ *
+ *
+ * If the class is unpackaged, return an empty string.
+ *
+ *
+ * @param className The className to get the package name for, may be {@code null}.
+ * @return The package name or an empty string.
+ */
+ public static String getPackageName(String className) {
+ if (StringUtils.isEmpty(className)) {
+ return StringUtils.EMPTY;
+ }
+ int i = 0;
+ // Strip array encoding
+ while (className.charAt(i) == '[') {
+ i++;
+ }
+ className = className.substring(i);
+ // Strip Object type encoding
+ if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') {
+ className = className.substring(1);
+ }
+ i = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR);
+ if (i == -1) {
+ return StringUtils.EMPTY;
+ }
+ return className.substring(0, i);
+ }
+
+ /**
+ * Gets the primitive class for the given class name, for example "byte".
+ *
+ * @param className The primitive class for the given class name.
+ * @return The primitive class.
+ */
+ static Class> getPrimitiveClass(final String className) {
+ return NAME_PRIMITIVE_MAP.get(className);
+ }
+
+ /**
+ * Gets the desired Method much like {@code Class.getMethod}, however it ensures that the returned Method is from a
+ * public class or interface and not from an anonymous inner class. This means that the Method is invokable and doesn't
+ * fall foul of Java bug (4071957).
+ *
+ *
+ * {@code Set set = Collections.unmodifiableSet(...);
+ * Method method = ClassUtils.getPublicMethod(set.getClass(), "isEmpty", new Class[0]);
+ * Object result = method.invoke(set, new Object[]);}
+ *
+ *
+ * @param cls The class to check, not null.
+ * @param methodName The name of the method.
+ * @param parameterTypes The list of parameters.
+ * @return The method.
+ * @throws NullPointerException if the class is null.
+ * @throws SecurityException if a security violation occurred.
+ * @throws NoSuchMethodException if the method is not found in the given class or if the method doesn't conform with the
+ * requirements.
+ */
+ public static Method getPublicMethod(final Class> cls, final String methodName, final Class>... parameterTypes) throws NoSuchMethodException {
final Method declaredMethod = cls.getMethod(methodName, parameterTypes);
- if (Modifier.isPublic(declaredMethod.getDeclaringClass().getModifiers())) {
+ if (isPublic(declaredMethod.getDeclaringClass())) {
return declaredMethod;
}
-
- final List> candidateClasses = new ArrayList<>();
- candidateClasses.addAll(getAllInterfaces(cls));
+ final List> candidateClasses = new ArrayList<>(getAllInterfaces(cls));
candidateClasses.addAll(getAllSuperclasses(cls));
-
for (final Class> candidateClass : candidateClasses) {
- if (!Modifier.isPublic(candidateClass.getModifiers())) {
+ if (!isPublic(candidateClass)) {
continue;
}
- Method candidateMethod;
- try {
- candidateMethod = candidateClass.getMethod(methodName, parameterTypes);
- } catch (final NoSuchMethodException ex) {
- continue;
+ final Method candidateMethod;
+ try {
+ candidateMethod = candidateClass.getMethod(methodName, parameterTypes);
+ } catch (final NoSuchMethodException ex) {
+ continue;
+ }
+ if (Modifier.isPublic(candidateMethod.getDeclaringClass().getModifiers())) {
+ return candidateMethod;
+ }
+ }
+ throw new NoSuchMethodException("Can't find a public method for " + methodName + " " + ArrayUtils.toString(parameterTypes));
+ }
+
+ /**
+ * Gets the canonical name minus the package name from a {@link Class}.
+ *
+ * @param cls The class for which to get the short canonical class name; may be null.
+ * @return The canonical name without the package name or an empty string.
+ * @since 2.4
+ * @see Class#getCanonicalName()
+ */
+ public static String getShortCanonicalName(final Class> cls) {
+ return cls == null ? StringUtils.EMPTY : getShortCanonicalName(cls.getCanonicalName());
+ }
+
+ /**
+ * Gets the canonical name minus the package name for an {@link Object}.
+ *
+ * @param object The class to get the short name for, may be null.
+ * @param valueIfNull The value to return if null.
+ * @return The canonical name of the object without the package name, or the null value.
+ * @since 2.4
+ * @see Class#getCanonicalName()
+ */
+ public static String getShortCanonicalName(final Object object, final String valueIfNull) {
+ return object == null ? valueIfNull : getShortCanonicalName(object.getClass());
+ }
+
+ /**
+ * Gets the canonical name minus the package name from a String.
+ *
+ *
+ * The string passed in is assumed to be a class name - it is not checked.
+ *
+ *
+ *
+ * Note that this method is mainly designed to handle the arrays and primitives properly. If the class is an inner class
+ * then the result value will not contain the outer classes. This way the behavior of this method is different from
+ * {@link #getShortClassName(String)}. The argument in that case is class name and not canonical name and the return
+ * value retains the outer classes.
+ *
+ *
+ *
+ * Note that there is no way to reliably identify the part of the string representing the package hierarchy and the part
+ * that is the outer class or classes in case of an inner class. Trying to find the class would require reflective call
+ * and the class itself may not even be on the class path. Relying on the fact that class names start with capital
+ * letter and packages with lower case is heuristic.
+ *
+ *
+ *
+ * It is recommended to use {@link #getShortClassName(String)} for cases when the class is an inner class and use this
+ * method for cases it is designed for.
+ *
+ *
+ * @param canonicalName The class name to get the short name for.
+ * @return The canonical name of the class without the package name or an empty string.
+ * @since 2.4
+ */
+ public static String getShortCanonicalName(final String canonicalName) {
+ return getShortClassName(getCanonicalName(canonicalName));
+ }
+
+ /**
+ * Gets the class name minus the package name from a {@link Class}.
+ *
+ * @param cls The class to get the short name for.
+ * @return The class name without the package name or an empty string. If the class is an inner class then the returned
+ * value will contain the outer class or classes separated with {@code .} (dot) character.
+ */
+ public static String getShortClassName(final Class> cls) {
+ if (cls == null) {
+ return StringUtils.EMPTY;
+ }
+ int dim = 0;
+ Class> c = cls;
+ while (c.isArray()) {
+ dim++;
+ c = c.getComponentType();
+ }
+ String base;
+ // c.isAnonymousClass() / isLocalClass() and the getDeclaringClass() chain
+ // can both throw NoClassDefFoundError when the enclosing class is
+ // missing from the classpath, so the try/catch wraps the whole block.
+ try {
+ // Preserve legacy behavior for anonymous/local classes (keeps compiler ordinals: $13, $10Named, etc.)
+ if (c.isAnonymousClass() || c.isLocalClass()) {
+ base = getShortClassName(c.getName());
+ } else {
+ final Deque parts = new ArrayDeque<>();
+ Class> x = c;
+ while (x != null) {
+ parts.push(x.getSimpleName());
+ x = x.getDeclaringClass();
+ }
+ base = String.join(".", parts);
+ }
+ } catch (final NoClassDefFoundError ignored) {
+ base = getShortClassName(c.getName());
+ }
+ return base + StringUtils.repeat("[]", dim);
+ }
+
+ /**
+ * Gets the class name of the {@code object} without the package name or names.
+ *
+ * @param object The class to get the short name for, may be {@code null}.
+ * @param valueIfNull The value to return if the object is {@code null}.
+ * @return The class name of the object without the package name, or {@code valueIfNull} if the argument {@code object}
+ * is {@code null}.
+ */
+ public static String getShortClassName(final Object object, final String valueIfNull) {
+ if (object == null) {
+ return valueIfNull;
+ }
+ return getShortClassName(object.getClass());
+ }
+
+ /**
+ * Gets the class name minus the package name from a String.
+ *
+ *
+ * The string passed in is assumed to be a class name - it is not checked. The string has to be formatted the way as the
+ * JDK method {@code Class.getName()} returns it, and not the usual way as we write it, for example in import
+ * statements, or as it is formatted by {@code Class.getCanonicalName()}.
+ *
+ *
+ *
+ * The difference is significant only in case of classes that are inner classes of some other classes. In this case
+ * the separator between the outer and inner class (possibly on multiple hierarchy level) has to be {@code $} (dollar
+ * sign) and not {@code .} (dot), as it is returned by {@code Class.getName()}
+ *
+ *
+ *
+ * Note that this method is called from the {@link #getShortClassName(Class)} method using the string returned by
+ * {@code Class.getName()}.
+ *
+ *
+ *
+ * Note that this method differs from {@link #getSimpleName(Class)} in that this will return, for example
+ * {@code "Map.Entry"} whilst the {@link Class} variant will simply return {@code "Entry"}. In this example
+ * the argument {@code className} is the string {@code java.util.Map$Entry} (note the {@code $} sign).
+ *
+ *
+ * @param className The className to get the short name for. It has to be formatted as returned by
+ * {@code Class.getName()} and not {@code Class.getCanonicalName()}.
+ * @return The class name of the class without the package name or an empty string. If the class is an inner class then
+ * value contains the outer class or classes and the separator is replaced to be {@code .} (dot) character.
+ */
+ public static String getShortClassName(String className) {
+ if (StringUtils.isEmpty(className)) {
+ return StringUtils.EMPTY;
+ }
+ final StringBuilder arrayPrefix = new StringBuilder();
+ // Handle array encoding
+ if (className.startsWith("[")) {
+ while (className.charAt(0) == '[') {
+ className = className.substring(1);
+ arrayPrefix.append("[]");
+ }
+ // Strip Object type encoding
+ if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') {
+ className = className.substring(1, className.length() - 1);
+ }
+ if (REVERSE_ABBREVIATION_MAP.containsKey(className)) {
+ className = REVERSE_ABBREVIATION_MAP.get(className);
+ }
+ }
+ final int lastDotIdx = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR);
+ final int innerIdx = className.indexOf(INNER_CLASS_SEPARATOR_CHAR, lastDotIdx == -1 ? 0 : lastDotIdx + 1);
+ String out = className.substring(lastDotIdx + 1);
+ if (innerIdx != -1) {
+ out = out.replace(INNER_CLASS_SEPARATOR_CHAR, PACKAGE_SEPARATOR_CHAR);
+ }
+ return out + arrayPrefix;
+ }
+
+ /**
+ * Null-safe version of {@code cls.getSimpleName()}
+ *
+ * @param cls The class for which to get the simple name; may be null.
+ * @return The simple class name or the empty string in case the argument is {@code null}.
+ * @since 3.0
+ * @see Class#getSimpleName()
+ */
+ public static String getSimpleName(final Class> cls) {
+ return getSimpleName(cls, StringUtils.EMPTY);
+ }
+
+ /**
+ * Null-safe version of {@code cls.getSimpleName()}
+ *
+ * @param cls The class for which to get the simple name; may be null.
+ * @param valueIfNull The value to return if null.
+ * @return The simple class name or {@code valueIfNull} if the argument {@code cls} is {@code null}.
+ * @since 3.0
+ * @see Class#getSimpleName()
+ */
+ public static String getSimpleName(final Class> cls, final String valueIfNull) {
+ return cls == null ? valueIfNull : cls.getSimpleName();
+ }
+
+ /**
+ * Null-safe version of {@code object.getClass().getSimpleName()}
+ *
+ *
+ * It is to note that this method is overloaded and in case the argument {@code object} is a {@link Class} object then
+ * the {@link #getSimpleName(Class)} will be invoked. If this is a significant possibility then the caller should check
+ * this case and call {@code
+ * getSimpleName(Class.class)} or just simply use the string literal {@code "Class"}, which is the result of the method
+ * in that case.
+ *
+ *
+ * @param object The object for which to get the simple class name; may be null.
+ * @return The simple class name or the empty string in case the argument is {@code null}.
+ * @since 3.7
+ * @see Class#getSimpleName()
+ */
+ public static String getSimpleName(final Object object) {
+ return getSimpleName(object, StringUtils.EMPTY);
+ }
+
+ /**
+ * Null-safe version of {@code object.getClass().getSimpleName()}
+ *
+ * @param object The object for which to get the simple class name; may be null.
+ * @param valueIfNull The value to return if {@code object} is {@code null}.
+ * @return The simple class name or {@code valueIfNull} if the argument {@code object} is {@code null}.
+ * @since 3.0
+ * @see Class#getSimpleName()
+ */
+ public static String getSimpleName(final Object object, final String valueIfNull) {
+ return object == null ? valueIfNull : object.getClass().getSimpleName();
+ }
+
+ /**
+ * Gets an {@link Iterable} that can iterate over a class hierarchy in ascending (subclass to superclass) order,
+ * excluding interfaces.
+ *
+ * @param type The type to get the class hierarchy from.
+ * @return Iterable an Iterable over the class hierarchy of the given class.
+ * @since 3.2
+ */
+ public static Iterable> hierarchy(final Class> type) {
+ return hierarchy(type, Interfaces.EXCLUDE);
+ }
+
+ /**
+ * Gets an {@link Iterable} that can iterate over a class hierarchy in ascending (subclass to superclass) order.
+ *
+ * @param type The type to get the class hierarchy from.
+ * @param interfacesBehavior switch indicating whether to include or exclude interfaces.
+ * @return Iterable an Iterable over the class hierarchy of the given class.
+ * @since 3.2
+ */
+ public static Iterable> hierarchy(final Class> type, final Interfaces interfacesBehavior) {
+ final Iterable> classes = () -> {
+ final AtomicReference> next = new AtomicReference<>(type);
+ return new Iterator>() {
+
+ @Override
+ public boolean hasNext() {
+ return next.get() != null;
+ }
+
+ @Override
+ public Class> next() {
+ return next.getAndUpdate(Class::getSuperclass);
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ };
+ };
+ if (interfacesBehavior != Interfaces.INCLUDE) {
+ return classes;
+ }
+ return () -> {
+ final Set> seenInterfaces = new HashSet<>();
+ final Iterator> wrapped = classes.iterator();
+
+ return new Iterator>() {
+ Iterator> interfaces = Collections.emptyIterator();
+
+ @Override
+ public boolean hasNext() {
+ return interfaces.hasNext() || wrapped.hasNext();
+ }
+
+ @Override
+ public Class> next() {
+ if (interfaces.hasNext()) {
+ final Class> nextInterface = interfaces.next();
+ seenInterfaces.add(nextInterface);
+ return nextInterface;
+ }
+ final Class> nextSuperclass = wrapped.next();
+ final Set> currentInterfaces = new LinkedHashSet<>();
+ walkInterfaces(currentInterfaces, nextSuperclass);
+ interfaces = currentInterfaces.iterator();
+ return nextSuperclass;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ private void walkInterfaces(final Set> addTo, final Class> c) {
+ for (final Class> iface : c.getInterfaces()) {
+ if (!seenInterfaces.contains(iface)) {
+ addTo.add(iface);
+ }
+ walkInterfaces(addTo, iface);
+ }
+ }
+
+ };
+ };
+ }
+
+ /**
+ * Tests whether one {@link Class} can be assigned to a variable of another {@link Class}.
+ *
+ *
+ * Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, this method takes into account widenings of
+ * primitive classes and {@code null}s.
+ *
+ *
+ *
+ * Primitive widenings allow an int to be assigned to a long, float or double. This method returns the correct result
+ * for these cases.
+ *
+ *
+ *
+ * {@code null} may be assigned to any reference type. This method will return {@code true} if {@code null} is passed in
+ * and the toClass is non-primitive.
+ *
+ *
+ *
+ * Specifically, this method tests whether the type represented by the specified {@link Class} parameter can be
+ * converted to the type represented by this {@link Class} object via an identity conversion widening primitive or
+ * widening reference conversion. See The Java Language
+ * Specification, sections 5.1.1, 5.1.2 and 5.1.4 for details.
+ *
+ *
+ *
+ * Since Lang 3.0, this method will default behavior for calculating assignability between primitive
+ * and wrapper types corresponding to the running Java version; i.e. autoboxing will be the default behavior in
+ * VMs running Java versions > 1.5.
+ *
+ *
+ * @param cls The Class to check, may be null.
+ * @param toClass The Class to try to assign into, returns false if null.
+ * @return {@code true} if assignment possible.
+ */
+ public static boolean isAssignable(final Class> cls, final Class> toClass) {
+ return isAssignable(cls, toClass, true);
+ }
+
+ /**
+ * Tests whether one {@link Class} can be assigned to a variable of another {@link Class}.
+ *
+ *
+ * Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, this method takes into account widenings of
+ * primitive classes and {@code null}s.
+ *
+ *
+ *
+ * Primitive widenings allow an int to be assigned to a long, float or double. This method returns the correct result
+ * for these cases.
+ *
+ *
+ *
+ * {@code null} may be assigned to any reference type. This method will return {@code true} if {@code null} is passed in
+ * and the toClass is non-primitive.
+ *
+ *
+ *
+ * Specifically, this method tests whether the type represented by the specified {@link Class} parameter can be
+ * converted to the type represented by this {@link Class} object via an identity conversion widening primitive or
+ * widening reference conversion. See The Java Language
+ * Specification, sections 5.1.1, 5.1.2 and 5.1.4 for details.
+ *
+ *
+ * @param cls The Class to check, may be null.
+ * @param toClass The Class to try to assign into, returns false if null.
+ * @param autoboxing whether to use implicit autoboxing/unboxing between primitives and wrappers.
+ * @return {@code true} if assignment possible.
+ */
+ public static boolean isAssignable(Class> cls, final Class> toClass, final boolean autoboxing) {
+ if (toClass == null) {
+ return false;
+ }
+ // have to check for null, as isAssignableFrom doesn't
+ if (cls == null) {
+ return !toClass.isPrimitive();
+ }
+ // autoboxing:
+ if (autoboxing) {
+ if (cls.isPrimitive() && !toClass.isPrimitive()) {
+ cls = primitiveToWrapper(cls);
+ if (cls == null) {
+ return false;
+ }
+ }
+ if (toClass.isPrimitive() && !cls.isPrimitive()) {
+ cls = wrapperToPrimitive(cls);
+ if (cls == null) {
+ return false;
+ }
+ }
+ }
+ if (cls.equals(toClass)) {
+ return true;
+ }
+ if (cls.isPrimitive()) {
+ if (!toClass.isPrimitive()) {
+ return false;
+ }
+ if (Integer.TYPE.equals(cls)) {
+ return Long.TYPE.equals(toClass) || Float.TYPE.equals(toClass) || Double.TYPE.equals(toClass);
+ }
+ if (Long.TYPE.equals(cls)) {
+ return Float.TYPE.equals(toClass) || Double.TYPE.equals(toClass);
+ }
+ if (Boolean.TYPE.equals(cls)) {
+ return false;
+ }
+ if (Double.TYPE.equals(cls)) {
+ return false;
+ }
+ if (Float.TYPE.equals(cls)) {
+ return Double.TYPE.equals(toClass);
+ }
+ if (Character.TYPE.equals(cls) || Short.TYPE.equals(cls)) {
+ return Integer.TYPE.equals(toClass) || Long.TYPE.equals(toClass) || Float.TYPE.equals(toClass) || Double.TYPE.equals(toClass);
}
- if (Modifier.isPublic(candidateMethod.getDeclaringClass().getModifiers())) {
- return candidateMethod;
+ if (Byte.TYPE.equals(cls)) {
+ return Short.TYPE.equals(toClass) || Integer.TYPE.equals(toClass) || Long.TYPE.equals(toClass) || Float.TYPE.equals(toClass)
+ || Double.TYPE.equals(toClass);
}
+ // should never get here
+ return false;
}
-
- throw new NoSuchMethodException("Can't find a public method for " +
- methodName + " " + ArrayUtils.toString(parameterTypes));
+ return toClass.isAssignableFrom(cls);
}
- // ----------------------------------------------------------------------
/**
- * Converts a class name to a JLS style class name.
+ * Tests whether an array of Classes can be assigned to another array of Classes.
+ *
+ *
+ * This method calls {@link #isAssignable(Class, Class) isAssignable} for each Class pair in the input arrays. It can be
+ * used to check if a set of arguments (the first parameter) are suitably compatible with a set of method parameter
+ * types (the second parameter).
+ *
+ *
+ *
+ * Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, this method takes into account widenings of
+ * primitive classes and {@code null}s.
+ *
+ *
+ *
+ * Primitive widenings allow an int to be assigned to a {@code long}, {@code float} or {@code double}. This method
+ * returns the correct result for these cases.
+ *
+ *
+ *
+ * {@code null} may be assigned to any reference type. This method will return {@code true} if {@code null} is passed in
+ * and the toClass is non-primitive.
+ *
+ *
+ *
+ * Specifically, this method tests whether the type represented by the specified {@link Class} parameter can be
+ * converted to the type represented by this {@link Class} object via an identity conversion widening primitive or
+ * widening reference conversion. See The Java Language
+ * Specification, sections 5.1.1, 5.1.2 and 5.1.4 for details.
+ *
+ *
+ *
+ * Since Lang 3.0, this method will default behavior for calculating assignability between primitive
+ * and wrapper types corresponding to the running Java version; i.e. autoboxing will be the default behavior in
+ * VMs running Java versions > 1.5.
+ *
*
- * @param className the class name
- * @return the converted name
+ * @param classArray The array of Classes to check, may be {@code null}.
+ * @param toClassArray The array of Classes to try to assign into, may be {@code null}.
+ * @return {@code true} if assignment possible.
*/
- private static String toCanonicalName(String className) {
- className = StringUtils.deleteWhitespace(className);
- Validate.notNull(className, "className must not be null.");
- if (className.endsWith("[]")) {
- final StringBuilder classNameBuffer = new StringBuilder();
- while (className.endsWith("[]")) {
- className = className.substring(0, className.length() - 2);
- classNameBuffer.append("[");
- }
- final String abbreviation = abbreviationMap.get(className);
- if (abbreviation != null) {
- classNameBuffer.append(abbreviation);
- } else {
- classNameBuffer.append("L").append(className).append(";");
- }
- className = classNameBuffer.toString();
- }
- return className;
+ public static boolean isAssignable(final Class>[] classArray, final Class>... toClassArray) {
+ return isAssignable(classArray, toClassArray, true);
}
/**
- *
Converts an array of {@code Object} in to an array of {@code Class} objects.
- * If any of these objects is null, a null element will be inserted into the array.
+ * Tests whether an array of Classes can be assigned to another array of Classes.
*
- *
This method returns {@code null} for a {@code null} input array.
+ *
+ * This method calls {@link #isAssignable(Class, Class) isAssignable} for each Class pair in the input arrays. It can be
+ * used to check if a set of arguments (the first parameter) are suitably compatible with a set of method parameter
+ * types (the second parameter).
+ *
*
- * @param array an {@code Object} array
- * @return a {@code Class} array, {@code null} if null array input
- * @since 2.4
+ *
+ * Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, this method takes into account widenings of
+ * primitive classes and {@code null}s.
+ *
+ *
+ *
+ * Primitive widenings allow an int to be assigned to a {@code long}, {@code float} or {@code double}. This method
+ * returns the correct result for these cases.
+ *
+ *
+ *
+ * {@code null} may be assigned to any reference type. This method will return {@code true} if {@code null} is passed in
+ * and the toClass is non-primitive.
+ *
+ *
+ *
+ * Specifically, this method tests whether the type represented by the specified {@link Class} parameter can be
+ * converted to the type represented by this {@link Class} object via an identity conversion widening primitive or
+ * widening reference conversion. See The Java Language
+ * Specification, sections 5.1.1, 5.1.2 and 5.1.4 for details.
+ *
+ *
+ * @param classArray The array of Classes to check, may be {@code null}
+ * @param toClassArray The array of Classes to try to assign into, may be {@code null}
+ * @param autoboxing whether to use implicit autoboxing/unboxing between primitives and wrappers
+ * @return {@code true} if assignment possible
*/
- public static Class>[] toClass(final Object... array) {
- if (array == null) {
- return null;
- } else if (array.length == 0) {
- return ArrayUtils.EMPTY_CLASS_ARRAY;
+ public static boolean isAssignable(Class>[] classArray, Class>[] toClassArray, final boolean autoboxing) {
+ if (!ArrayUtils.isSameLength(classArray, toClassArray)) {
+ return false;
}
- final Class>[] classes = new Class[array.length];
- for (int i = 0; i < array.length; i++) {
- classes[i] = array[i] == null ? null : array[i].getClass();
+ classArray = ArrayUtils.nullToEmpty(classArray);
+ toClassArray = ArrayUtils.nullToEmpty(toClassArray);
+ for (int i = 0; i < classArray.length; i++) {
+ if (!isAssignable(classArray[i], toClassArray[i], autoboxing)) {
+ return false;
+ }
}
- return classes;
+ return true;
}
- // Short canonical name
- // ----------------------------------------------------------------------
/**
- *
Gets the canonical name minus the package name for an {@code Object}.
+ * Tests whether the specified class an inner class or static nested class.
*
- * @param object the class to get the short name for, may be null
- * @param valueIfNull the value to return if null
- * @return the canonical name of the object without the package name, or the null value
- * @since 2.4
+ * @param cls The class to check, may be null.
+ * @return {@code true} if the class is an inner or static nested class, false if not or {@code null}.
*/
- public static String getShortCanonicalName(final Object object, final String valueIfNull) {
- if (object == null) {
- return valueIfNull;
- }
- return getShortCanonicalName(object.getClass().getName());
+ public static boolean isInnerClass(final Class> cls) {
+ return cls != null && cls.getEnclosingClass() != null;
}
/**
- *
Gets the canonical class name for a {@code Class}.
+ * Tests whether the given {@code type} is a primitive or primitive wrapper ({@link Boolean}, {@link Byte},
+ * {@link Character}, {@link Short}, {@link Integer}, {@link Long}, {@link Double}, {@link Float}).
*
- * @param cls the class for which to get the canonical class name; may be null
- * @return the canonical name of the class, or the empty String
- * @since 3.7
- * @see Class#getCanonicalName()
+ * @param type The class to query or null.
+ * @return true if the given {@code type} is a primitive or primitive wrapper ({@link Boolean}, {@link Byte},
+ * {@link Character}, {@link Short}, {@link Integer}, {@link Long}, {@link Double}, {@link Float}).
+ * @since 3.1
*/
- public static String getCanonicalName(final Class> cls) {
- return getCanonicalName(cls, StringUtils.EMPTY);
+ public static boolean isPrimitiveOrWrapper(final Class> type) {
+ return type != null && type.isPrimitive() || isPrimitiveWrapper(type);
}
/**
- *
Gets the canonical name for a {@code Class}.
+ * Tests whether the given {@code type} is a primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character},
+ * {@link Short}, {@link Integer}, {@link Long}, {@link Double}, {@link Float}).
*
- * @param cls the class for which to get the canonical class name; may be null
- * @param valueIfNull the return value if null
- * @return the canonical name of the class, or {@code valueIfNull}
- * @since 3.7
- * @see Class#getCanonicalName()
+ * @param type The class to query or null.
+ * @return true if the given {@code type} is a primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character},
+ * {@link Short}, {@link Integer}, {@link Long}, {@link Double}, {@link Float}).
+ * @since 3.1
*/
- public static String getCanonicalName(final Class> cls, final String valueIfNull) {
- if (cls == null) {
- return valueIfNull;
- }
- final String canonicalName = cls.getCanonicalName();
- return canonicalName == null ? valueIfNull : canonicalName;
+ public static boolean isPrimitiveWrapper(final Class> type) {
+ return WRAPPER_PRIMITIVE_MAP.containsKey(type);
}
/**
- *
Gets the canonical name for an {@code Object}.
+ * Tests whether a {@link Class} is public.
*
- * @param object the object for which to get the canonical class name; may be null
- * @return the canonical name of the object, or the empty String
- * @since 3.7
- * @see Class#getCanonicalName()
+ * @param cls Class to test.
+ * @return {@code true} if {@code cls} is public.
+ * @since 3.13.0
*/
- public static String getCanonicalName(final Object object) {
- return getCanonicalName(object, StringUtils.EMPTY);
+ public static boolean isPublic(final Class> cls) {
+ return Modifier.isPublic(cls.getModifiers());
}
/**
- *
Gets the canonical name for an {@code Object}.
+ * Converts the specified array of primitive Class objects to an array of its corresponding wrapper Class objects.
*
- * @param object the object for which to get the canonical class name; may be null
- * @param valueIfNull the return value if null
- * @return the canonical name of the object or {@code valueIfNull}
- * @since 3.7
- * @see Class#getCanonicalName()
+ * @param classes The class array to convert, may be null or empty.
+ * @return An array which contains for each given class, the wrapper class or the original class if class is not a primitive. {@code null} if null input.
+ * Empty array if an empty array passed in.
+ * @since 2.1
*/
- public static String getCanonicalName(final Object object, final String valueIfNull) {
- if (object == null) {
- return valueIfNull;
+ public static Class>[] primitivesToWrappers(final Class>... classes) {
+ if (classes == null) {
+ return null;
}
- final String canonicalName = object.getClass().getCanonicalName();
- return canonicalName == null ? valueIfNull : canonicalName;
+ if (classes.length == 0) {
+ return classes;
+ }
+ return ArrayUtils.setAll(new Class[classes.length], i -> primitiveToWrapper(classes[i]));
}
/**
- *
Gets the canonical name minus the package name from a {@code Class}.
+ * Converts the specified primitive Class object to its corresponding wrapper Class object.
*
- * @param cls the class for which to get the short canonical class name; may be null
- * @return the canonical name without the package name or an empty string
- * @since 2.4
+ *
+ * NOTE: From v2.2, this method handles {@code Void.TYPE}, returning {@code Void.TYPE}.
+ *
+ *
+ * @param cls The class to convert, may be null.
+ * @return The wrapper class for {@code cls} or {@code cls} if {@code cls} is not a primitive. {@code null} if null input.
+ * @since 2.1
*/
- public static String getShortCanonicalName(final Class> cls) {
- if (cls == null) {
- return StringUtils.EMPTY;
- }
- return getShortCanonicalName(cls.getName());
+ public static Class> primitiveToWrapper(final Class> cls) {
+ return cls != null && cls.isPrimitive() ? PRIMITIVE_WRAPPER_MAP.get(cls) : cls;
}
/**
- *
Gets the canonical name minus the package name from a String.
- *
- *
The string passed in is assumed to be a class name - it is not checked.
- *
- *
Note that this method is mainly designed to handle the arrays and primitives properly.
- * If the class is an inner class then the result value will not contain the outer classes.
- * This way the behavior of this method is different from {@link #getShortClassName(String)}.
- * The argument in that case is class name and not canonical name and the return value
- * retains the outer classes.
- *
- *
Note that there is no way to reliably identify the part of the string representing the
- * package hierarchy and the part that is the outer class or classes in case of an inner class.
- * Trying to find the class would require reflective call and the class itself may not even be
- * on the class path. Relying on the fact that class names start with capital letter and packages
- * with lower case is heuristic.
+ * Converts an array of {@link Object} in to an array of {@link Class} objects. If any of these objects is null, a null element will be inserted into the
+ * array.
*
- *
It is recommended to use {@link #getShortClassName(String)} for cases when the class
- * is an inner class and use this method for cases it is designed for.
+ * This method returns {@code null} for a {@code null} input array.
+ *
*
- * @param canonicalName the class name to get the short name for
- * @return the canonical name of the class without the package name or an empty string
+ * @param array An {@link Object} array.
+ * @return A {@link Class} array, {@code null} if null array input.
* @since 2.4
*/
- public static String getShortCanonicalName(final String canonicalName) {
- return getShortClassName(getCanonicalName(canonicalName));
+ public static Class>[] toClass(final Object... array) {
+ if (array == null) {
+ return null;
+ }
+ if (array.length == 0) {
+ return ArrayUtils.EMPTY_CLASS_ARRAY;
+ }
+ return ArrayUtils.setAll(new Class[array.length], i -> array[i] == null ? null : array[i].getClass());
}
- // Package name
- // ----------------------------------------------------------------------
/**
- *
Gets the package name from the class name of an {@code Object}.
+ * Converts and cleans up a class name to a JLS style class name.
+ *
+ * The provided class name is normalized by removing all whitespace. This is especially helpful when handling XML element values in which whitespace has not
+ * been collapsed.
+ *
*
- * @param object the class to get the package name for, may be null
- * @param valueIfNull the value to return if null
- * @return the package name of the object, or the null value
- * @since 2.4
- */
- public static String getPackageCanonicalName(final Object object, final String valueIfNull) {
- if (object == null) {
- return valueIfNull;
- }
- return getPackageCanonicalName(object.getClass().getName());
+ * @param className The class name.
+ * @return The converted name.
+ * @throws NullPointerException if the className is null.
+ * @throws IllegalArgumentException Thrown if the class name represents an array with more dimensions than the JVM supports, 255.
+ * @throws IllegalArgumentException Thrown if the class name length is greater than 65,535.
+ * @see JVM: Array dimension limits in JVM Specification
+ * CONSTANT_Class_info
+ * @see JLS: Fully Qualified Names and Canonical Names
+ * @see JLS: The Form of a Binary
+ */
+ private static String toCleanName(final String className) {
+ return toEncodedName(StringUtils.deleteWhitespace(className));
}
/**
- *
Gets the package name from the canonical name of a {@code Class}.
+ * Converts a class name to a JLS style class name without normalizing whitespace.
*
- * @param cls the class to get the package name for, may be {@code null}.
- * @return the package name or an empty string
- * @since 2.4
+ * @param className The class name.
+ * @return The converted name.
+ * @throws NullPointerException if the className is null.
+ * @throws IllegalArgumentException Thrown if the class name represents an array with more dimensions than the JVM supports, 255.
+ * @throws IllegalArgumentException Thrown if the class name length is greater than 65,535.
*/
- public static String getPackageCanonicalName(final Class> cls) {
- if (cls == null) {
- return StringUtils.EMPTY;
+ private static String toEncodedName(final String className) {
+ String canonicalName = className;
+ Objects.requireNonNull(canonicalName, "className");
+ if (canonicalName.isEmpty()) {
+ throw new IllegalArgumentException("Class name is empty");
}
- return getPackageCanonicalName(cls.getName());
+ final String encodedArrayOpen = "[";
+ final String encodedClassNameStart = "L";
+ final String encodedClassNameEnd = ";";
+ final boolean encodedName = canonicalName.startsWith(encodedArrayOpen) && canonicalName.endsWith(encodedClassNameEnd);
+ if (encodedName) {
+ final int arrIdx = canonicalName.indexOf(encodedClassNameStart);
+ if (arrIdx > MAX_JVM_ARRAY_DIMENSION) {
+ throw new IllegalArgumentException("Array dimension greater than JVM specification maximum of 255.");
+ }
+ if (arrIdx < 0) {
+ throw new IllegalArgumentException("Expected 'L' after '[' for an array style string.");
+ }
+ final int cnLen = canonicalName.length() - (arrIdx + 2); // account for the ending ';'
+ if (cnLen > MAX_CLASS_NAME_LENGTH) {
+ throw new IllegalArgumentException(String.format("Class name greater than maxium length %,d", MAX_CLASS_NAME_LENGTH));
+ }
+ }
+ final String arrayMarker = "[]";
+ final int arrIdx = canonicalName.indexOf(arrayMarker);
+ // The class name length without array markers.
+ final int cnLen = arrIdx > 0 ? arrIdx : canonicalName.length();
+ if (cnLen > MAX_CLASS_NAME_LENGTH && !encodedName) {
+ throw new IllegalArgumentException(String.format("Class name greater than maxium length %,d", MAX_CLASS_NAME_LENGTH));
+ }
+ if (canonicalName.endsWith(arrayMarker)) {
+ // Reject malformed inputs like "java.lang.String[]junk[]" or
+ // "java.lang.String[]][]" where the suffix is not composed of
+ // repeated "[]" pairs.
+ final String tail = canonicalName.substring(arrIdx);
+ if (!ARRAY_TAIL_PATTERN.matcher(tail).matches()) {
+ throw new IllegalArgumentException("Malformed array name: " + canonicalName);
+ }
+ final int dims = (canonicalName.length() - arrIdx) / 2;
+ if (dims > MAX_JVM_ARRAY_DIMENSION) {
+ throw new IllegalArgumentException("Array dimension greater than JVM specification maximum of 255.");
+ }
+ final StringBuilder classNameBuffer = new StringBuilder(StringUtils.repeat(encodedArrayOpen, dims));
+ canonicalName = canonicalName.substring(0, arrIdx);
+ final String abbreviation = ABBREVIATION_MAP.get(canonicalName);
+ if (abbreviation != null) {
+ classNameBuffer.append(abbreviation);
+ } else {
+ classNameBuffer.append(encodedClassNameStart).append(canonicalName).append(encodedClassNameEnd);
+ }
+ canonicalName = classNameBuffer.toString();
+ }
+ return canonicalName;
}
/**
- *
Gets the package name from the class name.
+ * Decides if the part that was just copied to its destination location in the work array can be kept as it was copied
+ * or must be abbreviated. It must be kept when the part is the last one, which is the simple name of the class. In this
+ * case the {@code source} index, from where the characters are copied points one position after the last character,
+ * a.k.a. {@code source ==
+ * originalLength}
*
- *
The string passed in is assumed to be a class name - it is not checked.
- *
If the class is in the default package, return an empty string.
+ *
+ * If the part is not the last one then it can be kept unabridged if the number of the characters copied so far plus the
+ * character that are to be copied is less than or equal to the desired length.
+ *
*
- * @param name the name to get the package name for, may be {@code null}
- * @return the package name or an empty string
- * @since 2.4
+ * @param runAheadTarget The target index (where the characters were copied to) pointing after the last character copied
+ * when the current part was copied.
+ * @param source The source index (where the characters were copied from) pointing after the last character copied when
+ * the current part was copied.
+ * @param originalLength The original length of the class full name, which is abbreviated.
+ * @param desiredLength The desired length of the abbreviated class name.
+ * @return {@code true} if it can be kept in its original length; {@code false} if the current part has to be abbreviated.
*/
- public static String getPackageCanonicalName(final String name) {
- return getPackageName(getCanonicalName(name));
+ private static boolean useFull(final int runAheadTarget, final int source, final int originalLength, final int desiredLength) {
+ return source >= originalLength || runAheadTarget + originalLength - source <= desiredLength;
}
/**
- *
Converts a given name of class into canonical format.
- * If name of class is not a name of array class it returns
- * unchanged name.
+ * Converts the specified array of wrapper Class objects to an array of its corresponding primitive Class objects.
*
- *
The method does not change the {@code $} separators in case
- * the class is inner class.
+ * This method invokes {@code wrapperToPrimitive()} for each element of the passed in array.
*
*
- * @param className the name of class
- * @return canonical form of class name
+ * @param classes The class array to convert, may be null or empty.
+ * @return An array which contains for each given class, the primitive class or {@code null} if the original class is not a wrapper class.
+ * {@code null} if null input. Empty array if an empty array passed in.
+ * @see #wrapperToPrimitive(Class)
* @since 2.4
*/
- private static String getCanonicalName(String className) {
- className = StringUtils.deleteWhitespace(className);
- if (className == null) {
+ public static Class>[] wrappersToPrimitives(final Class>... classes) {
+ if (classes == null) {
return null;
}
- int dim = 0;
- while (className.startsWith("[")) {
- dim++;
- className = className.substring(1);
- }
- if (dim < 1) {
- return className;
- }
- if (className.startsWith("L")) {
- className = className.substring(
- 1,
- className.endsWith(";")
- ? className.length() - 1
- : className.length());
- } else {
- if (!className.isEmpty()) {
- className = reverseAbbreviationMap.get(className.substring(0, 1));
- }
- }
- final StringBuilder canonicalClassNameBuffer = new StringBuilder(className);
- for (int i = 0; i < dim; i++) {
- canonicalClassNameBuffer.append("[]");
+ if (classes.length == 0) {
+ return classes;
}
- return canonicalClassNameBuffer.toString();
+ return ArrayUtils.setAll(new Class[classes.length], i -> wrapperToPrimitive(classes[i]));
}
/**
- * Get an {@link Iterable} that can iterate over a class hierarchy in ascending (subclass to superclass) order,
- * excluding interfaces.
+ * Converts the specified wrapper class to its corresponding primitive class.
*
- * @param type the type to get the class hierarchy from
- * @return Iterable an Iterable over the class hierarchy of the given class
- * @since 3.2
+ *
+ * This method is the counter part of {@code primitiveToWrapper()}. If the passed in class is a wrapper class for a
+ * primitive type, this primitive type will be returned (e.g. {@code Integer.TYPE} for {@code Integer.class}). For other
+ * classes, or if the parameter is {@code null}, the return value is {@code null}.
+ *
+ *
+ * @param cls The class to convert, may be {@code null}.
+ * @return The corresponding primitive type if {@code cls} is a wrapper class, {@code null} otherwise.
+ * @see #primitiveToWrapper(Class)
+ * @since 2.4
*/
- public static Iterable> hierarchy(final Class> type) {
- return hierarchy(type, Interfaces.EXCLUDE);
+ public static Class> wrapperToPrimitive(final Class> cls) {
+ return WRAPPER_PRIMITIVE_MAP.get(cls);
}
/**
- * Get an {@link Iterable} that can iterate over a class hierarchy in ascending (subclass to superclass) order.
+ * ClassUtils instances should NOT be constructed in standard programming. Instead, the class should be used as
+ * {@code ClassUtils.getShortClassName(cls)}.
*
- * @param type the type to get the class hierarchy from
- * @param interfacesBehavior switch indicating whether to include or exclude interfaces
- * @return Iterable an Iterable over the class hierarchy of the given class
- * @since 3.2
+ *
+ * This constructor is public to permit tools that require a JavaBean instance to operate.
+ *
+ *
+ * @deprecated TODO Make private in 4.0.
*/
- public static Iterable> hierarchy(final Class> type, final Interfaces interfacesBehavior) {
- final Iterable> classes = () -> {
- final MutableObject> next = new MutableObject<>(type);
- return new Iterator>() {
-
- @Override
- public boolean hasNext() {
- return next.getValue() != null;
- }
-
- @Override
- public Class> next() {
- final Class> result = next.getValue();
- next.setValue(result.getSuperclass());
- return result;
- }
-
- @Override
- public void remove() {
- throw new UnsupportedOperationException();
- }
-
- };
- };
- if (interfacesBehavior != Interfaces.INCLUDE) {
- return classes;
- }
- return () -> {
- final Set> seenInterfaces = new HashSet<>();
- final Iterator> wrapped = classes.iterator();
-
- return new Iterator>() {
- Iterator> interfaces = Collections.>emptySet().iterator();
-
- @Override
- public boolean hasNext() {
- return interfaces.hasNext() || wrapped.hasNext();
- }
-
- @Override
- public Class> next() {
- if (interfaces.hasNext()) {
- final Class> nextInterface = interfaces.next();
- seenInterfaces.add(nextInterface);
- return nextInterface;
- }
- final Class> nextSuperclass = wrapped.next();
- final Set> currentInterfaces = new LinkedHashSet<>();
- walkInterfaces(currentInterfaces, nextSuperclass);
- interfaces = currentInterfaces.iterator();
- return nextSuperclass;
- }
-
- private void walkInterfaces(final Set> addTo, final Class> c) {
- for (final Class> iface : c.getInterfaces()) {
- if (!seenInterfaces.contains(iface)) {
- addTo.add(iface);
- }
- walkInterfaces(addTo, iface);
- }
- }
-
- @Override
- public void remove() {
- throw new UnsupportedOperationException();
- }
-
- };
- };
+ @Deprecated
+ public ClassUtils() {
+ // empty
}
}
diff --git a/src/main/java/org/apache/commons/lang3/Conversion.java b/src/main/java/org/apache/commons/lang3/Conversion.java
index 18873d917b9..cf43e36c371 100644
--- a/src/main/java/org/apache/commons/lang3/Conversion.java
+++ b/src/main/java/org/apache/commons/lang3/Conversion.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,19 +14,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package org.apache.commons.lang3;
import java.util.UUID;
-
/**
- *
* Static methods to convert a type into another, with endianness and bit ordering awareness.
- *
+ *
*
- * The methods names follow a naming rule:
- * {@code [source endianness][source bit ordering]To[destination endianness][destination bit ordering]}
+ * The methods names follow a naming rule:
*
+ *
{@code
+ * [source endianness][source bit ordering]To[destination endianness][destination bit ordering]
+ * }
*
* Source/destination type fields is one of the following:
*
@@ -36,275 +37,170 @@
*
int or intArray
*
long or longArray
*
hex: a String containing hexadecimal digits (lowercase in destination)
- *
hexDigit: a Char containing a hexadecimal digit (lowercase in destination)
+ *
hexDigit: a {@code char} containing a hexadecimal digit (lowercase in destination)
*
uuid
*
*
- * Endianness field: little endian is the default, in this case the field is absent. In case of
- * big endian, the field is "Be". Bit ordering: Lsb0 is the default, in this case the field
- * is absent. In case of Msb0, the field is "Msb0".
+ * Endianness field: little-endian is the default, in this case the field is absent. In case of big-endian, the field is "Be".
+ *
+ *
+ * Bit ordering: LSB0 is the default, in this case the field is absent. In case of MSB0, the field is "Msb0" (Camel-case).
*
*
- * Example: intBeMsb0ToHex convert an int with big endian byte order and Msb0 bit order into its
- * hexadecimal string representation
+ * Example: intBeMsb0ToHex convert an {@code int} with big-endian byte order and MSB0 bit order into its hexadecimal string representation
*
*
- * Most of the methods provide only default encoding for destination, this limits the number of
- * ways to do one thing. Unless you are dealing with data from/to outside of the JVM platform,
- * you should not need to use "Be" and "Msb0" methods.
+ * Most of the methods provide only default encoding for destination, this limits the number of ways to do one thing. Unless you are dealing with data from/to
+ * outside of the JVM platform, you should not need to use "Be" and "Msb0" methods.
*
*
- * Development status: work on going, only a part of the little endian, Lsb0 methods implemented
- * so far.
+ * Development status: work on going, only a part of the little-endian, LSB0 methods implemented so far.
*
- * Converts a hexadecimal digit into an int using the default (Lsb0) bit ordering.
- *
- *
- * '1' is converted to 1
- *
+ * Converts the first 4 bits of a binary (represented as boolean array) in big-endian MSB0 bit ordering to a hexadecimal digit.
*
- * @param hexDigit the hexadecimal digit to convert
- * @return an int equals to {@code hexDigit}
- * @throws IllegalArgumentException if {@code hexDigit} is not a hexadecimal digit
- */
- public static int hexDigitToInt(final char hexDigit) {
- final int digit = Character.digit(hexDigit, 16);
- if (digit < 0) {
- throw new IllegalArgumentException("Cannot interpret '" + hexDigit + "' as a hexadecimal digit");
- }
- return digit;
- }
-
- /**
- *
- * Converts a hexadecimal digit into an int using the Msb0 bit ordering.
- *
*
- * '1' is converted to 8
+ * (1, 0, 0, 0) is converted as follow: '8' (1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0) is converted to '4'.
*
*
- * @param hexDigit the hexadecimal digit to convert
- * @return an int equals to {@code hexDigit}
- * @throws IllegalArgumentException if {@code hexDigit} is not a hexadecimal digit
+ * @param src The binary to convert.
+ * @return A hexadecimal digit representing the selected bits.
+ * @throws IllegalArgumentException if {@code src} is empty.
+ * @throws NullPointerException if {@code src} is {@code null}.
*/
- public static int hexDigitMsb0ToInt(final char hexDigit) {
- switch (hexDigit) {
- case '0':
- return 0x0;
- case '1':
- return 0x8;
- case '2':
- return 0x4;
- case '3':
- return 0xC;
- case '4':
- return 0x2;
- case '5':
- return 0xA;
- case '6':
- return 0x6;
- case '7':
- return 0xE;
- case '8':
- return 0x1;
- case '9':
- return 0x9;
- case 'a':// fall through
- case 'A':
- return 0x5;
- case 'b':// fall through
- case 'B':
- return 0xD;
- case 'c':// fall through
- case 'C':
- return 0x3;
- case 'd':// fall through
- case 'D':
- return 0xB;
- case 'e':// fall through
- case 'E':
- return 0x7;
- case 'f':// fall through
- case 'F':
- return 0xF;
- default:
- throw new IllegalArgumentException("Cannot interpret '" + hexDigit + "' as a hexadecimal digit");
- }
+ public static char binaryBeMsb0ToHexDigit(final boolean[] src) {
+ return binaryBeMsb0ToHexDigit(src, 0);
}
/**
+ * Converts a binary (represented as boolean array) in big-endian MSB0 bit ordering to a hexadecimal digit.
+ *
*
- * Converts a hexadecimal digit into binary (represented as boolean array) using the default
- * (Lsb0) bit ordering.
- *
- *
- * '1' is converted as follow: (1, 0, 0, 0)
+ * (1, 0, 0, 0) with srcPos = 0 is converted as follow: '8' (1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0) with srcPos = 2 is converted to '5'.
*
*
- * @param hexDigit the hexadecimal digit to convert
- * @return a boolean array with the binary representation of {@code hexDigit}
- * @throws IllegalArgumentException if {@code hexDigit} is not a hexadecimal digit
+ * @param src The binary to convert.
+ * @param srcPos The position of the LSB to start the conversion.
+ * @return A hexadecimal digit representing the selected bits.
+ * @throws IllegalArgumentException if {@code src} is empty.
+ * @throws NullPointerException if {@code src} is {@code null}.
+ * @throws IndexOutOfBoundsException if {@code srcPos} is outside the array.
*/
- public static boolean[] hexDigitToBinary(final char hexDigit) {
- switch (hexDigit) {
- case '0':
- return FFFF.clone();
- case '1':
- return TFFF.clone();
- case '2':
- return FTFF.clone();
- case '3':
- return TTFF.clone();
- case '4':
- return FFTF.clone();
- case '5':
- return TFTF.clone();
- case '6':
- return FTTF.clone();
- case '7':
- return TTTF.clone();
- case '8':
- return FFFT.clone();
- case '9':
- return TFFT.clone();
- case 'a':// fall through
- case 'A':
- return FTFT.clone();
- case 'b':// fall through
- case 'B':
- return TTFT.clone();
- case 'c':// fall through
- case 'C':
- return FFTT.clone();
- case 'd':// fall through
- case 'D':
- return TFTT.clone();
- case 'e':// fall through
- case 'E':
- return FTTT.clone();
- case 'f':// fall through
- case 'F':
- return TTTT.clone();
- default:
- throw new IllegalArgumentException("Cannot interpret '" + hexDigit + "' as a hexadecimal digit");
+ public static char binaryBeMsb0ToHexDigit(final boolean[] src, final int srcPos) {
+ // JDK 9: Objects.checkIndex(int index, int length)
+ if (Integer.compareUnsigned(srcPos, src.length) >= 0) {
+ // Throw the correct exception
+ if (src.length == 0) {
+ throw new IllegalArgumentException("Cannot convert an empty array.");
+ }
+ throw new IndexOutOfBoundsException(srcPos + " is not within array length " + src.length);
+ }
+ // Little-endian bit 0 position
+ final int pos = src.length - 1 - srcPos;
+ if (3 <= pos && src[pos - 3]) {
+ if (src[pos - 2]) {
+ if (src[pos - 1]) {
+ return src[pos] ? 'f' : 'e';
+ }
+ return src[pos] ? 'd' : 'c';
+ }
+ if (src[pos - 1]) {
+ return src[pos] ? 'b' : 'a';
+ }
+ return src[pos] ? '9' : '8';
+ }
+ if (2 <= pos && src[pos - 2]) {
+ if (src[pos - 1]) {
+ return src[pos] ? '7' : '6';
+ }
+ return src[pos] ? '5' : '4';
+ }
+ if (1 <= pos && src[pos - 1]) {
+ return src[pos] ? '3' : '2';
}
+ return src[pos] ? '1' : '0';
}
/**
- *
- * Converts a hexadecimal digit into binary (represented as boolean array) using the Msb0
- * bit ordering.
- *
- *
- * '1' is converted as follow: (0, 0, 0, 1)
- *
+ * Converts binary (represented as boolean array) into a byte using the default (little-endian, LSB0) byte and bit ordering.
*
- * @param hexDigit the hexadecimal digit to convert
- * @return a boolean array with the binary representation of {@code hexDigit}
- * @throws IllegalArgumentException if {@code hexDigit} is not a hexadecimal digit
+ * @param src The binary to convert.
+ * @param srcPos The position in {@code src}, in boolean unit, from where to start the conversion.
+ * @param dstInit initial value of the destination byte.
+ * @param dstPos The position of the LSB, in bits, in the result byte.
+ * @param nBools The number of booleans to convert.
+ * @return A byte containing the selected bits.
+ * @throws NullPointerException if {@code src} is {@code null}.
+ * @throws IllegalArgumentException if {@code nBools - 1 + dstPos >= 8}.
+ * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBools > src.length}.
*/
- public static boolean[] hexDigitMsb0ToBinary(final char hexDigit) {
- switch (hexDigit) {
- case '0':
- return FFFF.clone();
- case '1':
- return FFFT.clone();
- case '2':
- return FFTF.clone();
- case '3':
- return FFTT.clone();
- case '4':
- return FTFF.clone();
- case '5':
- return FTFT.clone();
- case '6':
- return FTTF.clone();
- case '7':
- return FTTT.clone();
- case '8':
- return TFFF.clone();
- case '9':
- return TFFT.clone();
- case 'a':// fall through
- case 'A':
- return TFTF.clone();
- case 'b':// fall through
- case 'B':
- return TFTT.clone();
- case 'c':// fall through
- case 'C':
- return TTFF.clone();
- case 'd':// fall through
- case 'D':
- return TTFT.clone();
- case 'e':// fall through
- case 'E':
- return TTTF.clone();
- case 'f':// fall through
- case 'F':
- return TTTT.clone();
- default:
- throw new IllegalArgumentException("Cannot interpret '" + hexDigit + "' as a hexadecimal digit");
+ public static byte binaryToByte(final boolean[] src, final int srcPos, final byte dstInit, final int dstPos, final int nBools) {
+ if (src.length == 0 && srcPos == 0 || 0 == nBools) {
+ return dstInit;
+ }
+ if ((long) nBools - 1 + dstPos >= Byte.SIZE) {
+ throw new IllegalArgumentException("nBools - 1 + dstPos >= 8");
+ }
+ byte out = dstInit;
+ for (int i = 0; i < nBools; i++) {
+ final int shift = i + dstPos;
+ final int bits = (src[i + srcPos] ? 1 : 0) << shift;
+ final int mask = 0x1 << shift;
+ out = (byte) (out & ~mask | bits);
}
+ return out;
}
/**
+ * Converts binary (represented as boolean array) to a hexadecimal digit using the default (LSB0) bit ordering.
+ *
*
- * Converts binary (represented as boolean array) to a hexadecimal digit using the default
- * (Lsb0) bit ordering.
- *
- *
- * (1, 0, 0, 0) is converted as follow: '1'
+ * (1, 0, 0, 0) is converted as follow: '1'.
*
*
- * @param src the binary to convert
- * @return a hexadecimal digit representing the selected bits
- * @throws IllegalArgumentException if {@code src} is empty
- * @throws NullPointerException if {@code src} is {@code null}
+ * @param src The binary to convert.
+ * @return A hexadecimal digit representing the selected bits.
+ * @throws IllegalArgumentException if {@code src} is empty.
+ * @throws NullPointerException if {@code src} is {@code null}.
*/
public static char binaryToHexDigit(final boolean[] src) {
return binaryToHexDigit(src, 0);
}
/**
+ * Converts binary (represented as boolean array) to a hexadecimal digit using the default (LSB0) bit ordering.
+ *
*
- * Converts binary (represented as boolean array) to a hexadecimal digit using the default
- * (Lsb0) bit ordering.
- *
- *
- * (1, 0, 0, 0) is converted as follow: '1'
+ * (1, 0, 0, 0) is converted as follow: '1'.
*
*
- * @param src the binary to convert
- * @param srcPos the position of the lsb to start the conversion
- * @return a hexadecimal digit representing the selected bits
- * @throws IllegalArgumentException if {@code src} is empty
- * @throws NullPointerException if {@code src} is {@code null}
+ * @param src The binary to convert.
+ * @param srcPos The position of the LSB to start the conversion.
+ * @return A hexadecimal digit representing the selected bits.
+ * @throws IllegalArgumentException if {@code src} is empty.
+ * @throws NullPointerException if {@code src} is {@code null}.
*/
public static char binaryToHexDigit(final boolean[] src, final int srcPos) {
if (src.length == 0) {
@@ -335,47 +231,40 @@ public static char binaryToHexDigit(final boolean[] src, final int srcPos) {
}
/**
+ * Converts binary (represented as boolean array) to a hexadecimal digit using the MSB0 bit ordering.
+ *
*
- * Converts binary (represented as boolean array) to a hexadecimal digit using the Msb0 bit
- * ordering.
- *
- *
- * (1, 0, 0, 0) is converted as follow: '8'
+ * (1, 0, 0, 0) is converted as follow: '8'.
*
*
- * @param src the binary to convert
- * @return a hexadecimal digit representing the selected bits
- * @throws IllegalArgumentException if {@code src} is empty, {@code src.length < 4} or
- * {@code src.length > 8}
- * @throws NullPointerException if {@code src} is {@code null}
+ * @param src The binary to convert.
+ * @return A hexadecimal digit representing the selected bits.
+ * @throws IllegalArgumentException if {@code src} is empty, {@code src.length < 4} or {@code src.length > 8}.
+ * @throws NullPointerException if {@code src} is {@code null}.
*/
public static char binaryToHexDigitMsb0_4bits(final boolean[] src) {
return binaryToHexDigitMsb0_4bits(src, 0);
}
/**
+ * Converts binary (represented as boolean array) to a hexadecimal digit using the MSB0 bit ordering.
+ *
*
- * Converts binary (represented as boolean array) to a hexadecimal digit using the Msb0 bit
- * ordering.
- *
- *
- * (1, 0, 0, 0) is converted as follow: '8' (1, 0, 0, 1, 1, 0, 1, 0) with srcPos = 3 is converted
- * to 'D'
+ * (1, 0, 0, 0) is converted as follow: '8' (1, 0, 0, 1, 1, 0, 1, 0) with srcPos = 3 is converted to 'D'
*
*
- * @param src the binary to convert
- * @param srcPos the position of the lsb to start the conversion
- * @return a hexadecimal digit representing the selected bits
- * @throws IllegalArgumentException if {@code src} is empty, {@code src.length > 8} or
- * {@code src.length - srcPos < 4}
- * @throws NullPointerException if {@code src} is {@code null}
+ * @param src The binary to convert.
+ * @param srcPos The position of the LSB to start the conversion.
+ * @return A hexadecimal digit representing the selected bits.
+ * @throws IllegalArgumentException if {@code src} is empty, {@code src.length > 8} or {@code src.length - srcPos < 4}.
+ * @throws NullPointerException if {@code src} is {@code null}.
*/
public static char binaryToHexDigitMsb0_4bits(final boolean[] src, final int srcPos) {
- if (src.length > 8) {
- throw new IllegalArgumentException("src.length>8: src.length=" + src.length);
+ if (src.length > Byte.SIZE) {
+ throw new IllegalArgumentException("src.length > 8: src.length=" + src.length);
}
if (src.length - srcPos < 4) {
- throw new IllegalArgumentException("src.length-srcPos<4: src.length=" + src.length + ", srcPos=" + srcPos);
+ throw new IllegalArgumentException("src.length - srcPos < 4: src.length=" + src.length + ", srcPos=" + srcPos);
}
if (src[srcPos + 3]) {
if (src[srcPos + 2]) {
@@ -402,859 +291,864 @@ public static char binaryToHexDigitMsb0_4bits(final boolean[] src, final int src
}
/**
- *
- * Converts the first 4 bits of a binary (represented as boolean array) in big endian Msb0
- * bit ordering to a hexadecimal digit.
- *
- *
- * (1, 0, 0, 0) is converted as follow: '8' (1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0) is converted
- * to '4'
- *
+ * Converts binary (represented as boolean array) into an int using the default (little endian, LSB0) byte and bit ordering.
*
- * @param src the binary to convert
- * @return a hexadecimal digit representing the selected bits
- * @throws IllegalArgumentException if {@code src} is empty
- * @throws NullPointerException if {@code src} is {@code null}
+ * @param src The binary to convert.
+ * @param srcPos The position in {@code src}, in boolean unit, from where to start the conversion.
+ * @param dstInit initial value of the destination int.
+ * @param dstPos The position of the LSB, in bits, in the result int.
+ * @param nBools The number of booleans to convert.
+ * @return An int containing the selected bits.
+ * @throws NullPointerException if {@code src} is {@code null}.
+ * @throws IllegalArgumentException if {@code nBools - 1 + dstPos >= 32}.
+ * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBools > src.length}.
*/
- public static char binaryBeMsb0ToHexDigit(final boolean[] src) {
- return binaryBeMsb0ToHexDigit(src, 0);
+ public static int binaryToInt(final boolean[] src, final int srcPos, final int dstInit, final int dstPos, final int nBools) {
+ if (src.length == 0 && srcPos == 0 || 0 == nBools) {
+ return dstInit;
+ }
+ if ((long) nBools - 1 + dstPos >= Integer.SIZE) {
+ throw new IllegalArgumentException("nBools - 1 + dstPos >= 32");
+ }
+ int out = dstInit;
+ for (int i = 0; i < nBools; i++) {
+ final int shift = i + dstPos;
+ final int bits = (src[i + srcPos] ? 1 : 0) << shift;
+ final int mask = 0x1 << shift;
+ out = out & ~mask | bits;
+ }
+ return out;
}
/**
- *
- * Converts a binary (represented as boolean array) in big endian Msb0 bit ordering to a
- * hexadecimal digit.
- *
- *
- * (1, 0, 0, 0) with srcPos = 0 is converted as follow: '8' (1, 0, 0, 0, 0, 0, 0, 0,
- * 0, 0, 0, 1, 0, 1, 0, 0) with srcPos = 2 is converted to '5'
- *
+ * Converts binary (represented as boolean array) into a long using the default (little endian, LSB0) byte and bit ordering.
*
- * @param src the binary to convert
- * @param srcPos the position of the lsb to start the conversion
- * @return a hexadecimal digit representing the selected bits
- * @throws IllegalArgumentException if {@code src} is empty
- * @throws NullPointerException if {@code src} is {@code null}
+ * @param src The binary to convert.
+ * @param srcPos The position in {@code src}, in boolean unit, from where to start the conversion.
+ * @param dstInit initial value of the destination long.
+ * @param dstPos The position of the LSB, in bits, in the result long.
+ * @param nBools The number of booleans to convert.
+ * @return A long containing the selected bits.
+ * @throws NullPointerException if {@code src} is {@code null}.
+ * @throws IllegalArgumentException if {@code nBools - 1 + dstPos >= 64}.
+ * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBools > src.length}.
*/
- public static char binaryBeMsb0ToHexDigit(boolean[] src, int srcPos) {
- if (src.length == 0) {
- throw new IllegalArgumentException("Cannot convert an empty array.");
- }
- final int beSrcPos = src.length - 1 - srcPos;
- final int srcLen = Math.min(4, beSrcPos + 1);
- final boolean[] paddedSrc = new boolean[4];
- System.arraycopy(src, beSrcPos + 1 - srcLen, paddedSrc, 4 - srcLen, srcLen);
- src = paddedSrc;
- srcPos = 0;
- if (src[srcPos]) {
- if (src.length > srcPos + 1 && src[srcPos + 1]) {
- if (src.length > srcPos + 2 && src[srcPos + 2]) {
- return src.length > srcPos + 3 && src[srcPos + 3] ? 'f' : 'e';
- }
- return src.length > srcPos + 3 && src[srcPos + 3] ? 'd' : 'c';
- }
- if (src.length > srcPos + 2 && src[srcPos + 2]) {
- return src.length > srcPos + 3 && src[srcPos + 3] ? 'b' : 'a';
- }
- return src.length > srcPos + 3 && src[srcPos + 3] ? '9' : '8';
+ public static long binaryToLong(final boolean[] src, final int srcPos, final long dstInit, final int dstPos, final int nBools) {
+ if (src.length == 0 && srcPos == 0 || 0 == nBools) {
+ return dstInit;
}
- if (src.length > srcPos + 1 && src[srcPos + 1]) {
- if (src.length > srcPos + 2 && src[srcPos + 2]) {
- return src.length > srcPos + 3 && src[srcPos + 3] ? '7' : '6';
- }
- return src.length > srcPos + 3 && src[srcPos + 3] ? '5' : '4';
+ if ((long) nBools - 1 + dstPos >= Long.SIZE) {
+ throw new IllegalArgumentException("nBools - 1 + dstPos >= 64");
}
- if (src.length > srcPos + 2 && src[srcPos + 2]) {
- return src.length > srcPos + 3 && src[srcPos + 3] ? '3' : '2';
+ long out = dstInit;
+ for (int i = 0; i < nBools; i++) {
+ final int shift = i + dstPos;
+ final long bits = (src[i + srcPos] ? 1L : 0) << shift;
+ final long mask = 0x1L << shift;
+ out = out & ~mask | bits;
}
- return src.length > srcPos + 3 && src[srcPos + 3] ? '1' : '0';
+ return out;
}
/**
- *
- * Converts the 4 lsb of an int to a hexadecimal digit.
- *
- *
- * 0 returns '0'
- *
- *
- * 1 returns '1'
- *
- *
- * 10 returns 'A' and so on...
- *
+ * Converts binary (represented as boolean array) into a short using the default (little endian, LSB0) byte and bit ordering.
*
- * @param nibble the 4 bits to convert
- * @return a hexadecimal digit representing the 4 lsb of {@code nibble}
- * @throws IllegalArgumentException if {@code nibble < 0} or {@code nibble > 15}
+ * @param src The binary to convert.
+ * @param srcPos The position in {@code src}, in boolean unit, from where to start the conversion.
+ * @param dstInit initial value of the destination short.
+ * @param dstPos The position of the LSB, in bits, in the result short.
+ * @param nBools The number of booleans to convert.
+ * @return A short containing the selected bits.
+ * @throws NullPointerException if {@code src} is {@code null}.
+ * @throws IllegalArgumentException if {@code nBools - 1 + dstPos >= 16}.
+ * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBools > src.length}.
*/
- public static char intToHexDigit(final int nibble) {
- final char c = Character.forDigit(nibble, 16);
- if (c == Character.MIN_VALUE) {
- throw new IllegalArgumentException("nibble value not between 0 and 15: " + nibble);
+ public static short binaryToShort(final boolean[] src, final int srcPos, final short dstInit, final int dstPos, final int nBools) {
+ if (src.length == 0 && srcPos == 0 || 0 == nBools) {
+ return dstInit;
}
- return c;
+ if ((long) nBools - 1 + dstPos >= Short.SIZE) {
+ throw new IllegalArgumentException("nBools - 1 + dstPos >= 16");
+ }
+ short out = dstInit;
+ for (int i = 0; i < nBools; i++) {
+ final int shift = i + dstPos;
+ final int bits = (src[i + srcPos] ? 1 : 0) << shift;
+ final int mask = 0x1 << shift;
+ out = (short) (out & ~mask | bits);
+ }
+ return out;
}
/**
- *
- * Converts the 4 lsb of an int to a hexadecimal digit encoded using the Msb0 bit ordering.
- *
- *
- * 0 returns '0'
- *
- *
- * 1 returns '8'
- *
- *
- * 10 returns '5' and so on...
- *
+ * Converts an array of byte into an int using the default (little-endian, LSB0) byte and bit ordering.
*
- * @param nibble the 4 bits to convert
- * @return a hexadecimal digit representing the 4 lsb of {@code nibble}
- * @throws IllegalArgumentException if {@code nibble < 0} or {@code nibble > 15}
+ * @param src The byte array to convert.
+ * @param srcPos The position in {@code src}, in byte unit, from where to start the conversion.
+ * @param dstInit initial value of the destination int.
+ * @param dstPos The position of the LSB, in bits, in the result int.
+ * @param nBytes The number of bytes to convert.
+ * @return An int containing the selected bits.
+ * @throws NullPointerException if {@code src} is {@code null}.
+ * @throws IllegalArgumentException if {@code (nBytes - 1) * 8 + dstPos >= 32}.
+ * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBytes > src.length}.
*/
- public static char intToHexDigitMsb0(final int nibble) {
- switch (nibble) {
- case 0x0:
- return '0';
- case 0x1:
- return '8';
- case 0x2:
- return '4';
- case 0x3:
- return 'c';
- case 0x4:
- return '2';
- case 0x5:
- return 'a';
- case 0x6:
- return '6';
- case 0x7:
- return 'e';
- case 0x8:
- return '1';
- case 0x9:
- return '9';
- case 0xA:
- return '5';
- case 0xB:
- return 'd';
- case 0xC:
- return '3';
- case 0xD:
- return 'b';
- case 0xE:
- return '7';
- case 0xF:
- return 'f';
- default:
- throw new IllegalArgumentException("nibble value not between 0 and 15: " + nibble);
+ public static int byteArrayToInt(final byte[] src, final int srcPos, final int dstInit, final int dstPos, final int nBytes) {
+ if (src.length == 0 && srcPos == 0 || 0 == nBytes) {
+ return dstInit;
+ }
+ if (((long) nBytes - 1) * Byte.SIZE + dstPos >= Integer.SIZE) {
+ throw new IllegalArgumentException("(nBytes - 1) * 8 + dstPos >= 32");
+ }
+ int out = dstInit;
+ for (int i = 0; i < nBytes; i++) {
+ final int shift = i * Byte.SIZE + dstPos;
+ final int bits = (0xff & src[i + srcPos]) << shift;
+ final int mask = 0xff << shift;
+ out = out & ~mask | bits;
}
+ return out;
}
/**
- *
- * Converts an array of int into a long using the default (little endian, Lsb0) byte and bit
- * ordering.
- *
+ * Converts an array of byte into a long using the default (little-endian, LSB0) byte and bit ordering.
*
- * @param src the int array to convert
- * @param srcPos the position in {@code src}, in int unit, from where to start the
- * conversion
- * @param dstInit initial value of the destination long
- * @param dstPos the position of the lsb, in bits, in the result long
- * @param nInts the number of ints to convert
- * @return a long containing the selected bits
- * @throws IllegalArgumentException if {@code (nInts-1)*32+dstPos >= 64}
- * @throws NullPointerException if {@code src} is {@code null}
- * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nInts > src.length}
+ * @param src The byte array to convert.
+ * @param srcPos The position in {@code src}, in byte unit, from where to start the conversion.
+ * @param dstInit initial value of the destination long.
+ * @param dstPos The position of the LSB, in bits, in the result long.
+ * @param nBytes The number of bytes to convert.
+ * @return A long containing the selected bits.
+ * @throws NullPointerException if {@code src} is {@code null}.
+ * @throws IllegalArgumentException if {@code (nBytes - 1) * 8 + dstPos >= 64}.
+ * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBytes > src.length}.
*/
- public static long intArrayToLong(final int[] src, final int srcPos, final long dstInit, final int dstPos,
- final int nInts) {
- if (src.length == 0 && srcPos == 0 || 0 == nInts) {
+ public static long byteArrayToLong(final byte[] src, final int srcPos, final long dstInit, final int dstPos, final int nBytes) {
+ if (src.length == 0 && srcPos == 0 || 0 == nBytes) {
return dstInit;
}
- if ((nInts - 1) * 32 + dstPos >= 64) {
- throw new IllegalArgumentException("(nInts-1)*32+dstPos is greater or equal to than 64");
+ if (((long) nBytes - 1) * Byte.SIZE + dstPos >= Long.SIZE) {
+ throw new IllegalArgumentException("(nBytes - 1) * 8 + dstPos >= 64");
}
long out = dstInit;
- for (int i = 0; i < nInts; i++) {
- final int shift = i * 32 + dstPos;
- final long bits = (0xffffffffL & src[i + srcPos]) << shift;
- final long mask = 0xffffffffL << shift;
- out = (out & ~mask) | bits;
+ for (int i = 0; i < nBytes; i++) {
+ final int shift = i * Byte.SIZE + dstPos;
+ final long bits = (0xffL & src[i + srcPos]) << shift;
+ final long mask = 0xffL << shift;
+ out = out & ~mask | bits;
}
return out;
}
/**
- *
- * Converts an array of short into a long using the default (little endian, Lsb0) byte and
- * bit ordering.
- *
+ * Converts an array of byte into a short using the default (little-endian, LSB0) byte and bit ordering.
*
- * @param src the short array to convert
- * @param srcPos the position in {@code src}, in short unit, from where to start the
- * conversion
- * @param dstInit initial value of the destination long
- * @param dstPos the position of the lsb, in bits, in the result long
- * @param nShorts the number of shorts to convert
- * @return a long containing the selected bits
- * @throws NullPointerException if {@code src} is {@code null}
- * @throws IllegalArgumentException if {@code (nShorts-1)*16+dstPos >= 64}
- * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nShorts > src.length}
+ * @param src The byte array to convert.
+ * @param srcPos The position in {@code src}, in byte unit, from where to start the conversion.
+ * @param dstInit initial value of the destination short.
+ * @param dstPos The position of the LSB, in bits, in the result short.
+ * @param nBytes The number of bytes to convert.
+ * @return A short containing the selected bits.
+ * @throws NullPointerException if {@code src} is {@code null}.
+ * @throws IllegalArgumentException if {@code (nBytes - 1) * 8 + dstPos >= 16}.
+ * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBytes > src.length}.
*/
- public static long shortArrayToLong(final short[] src, final int srcPos, final long dstInit, final int dstPos,
- final int nShorts) {
- if (src.length == 0 && srcPos == 0 || 0 == nShorts) {
+ public static short byteArrayToShort(final byte[] src, final int srcPos, final short dstInit, final int dstPos, final int nBytes) {
+ if (src.length == 0 && srcPos == 0 || 0 == nBytes) {
return dstInit;
}
- if ((nShorts - 1) * 16 + dstPos >= 64) {
- throw new IllegalArgumentException("(nShorts-1)*16+dstPos is greater or equal to than 64");
+ if (((long) nBytes - 1) * Byte.SIZE + dstPos >= Short.SIZE) {
+ throw new IllegalArgumentException("(nBytes - 1) * 8 + dstPos >= 16");
}
- long out = dstInit;
- for (int i = 0; i < nShorts; i++) {
- final int shift = i * 16 + dstPos;
- final long bits = (0xffffL & src[i + srcPos]) << shift;
- final long mask = 0xffffL << shift;
- out = (out & ~mask) | bits;
+ short out = dstInit;
+ for (int i = 0; i < nBytes; i++) {
+ final int shift = i * Byte.SIZE + dstPos;
+ final int bits = (0xff & src[i + srcPos]) << shift;
+ final int mask = 0xff << shift;
+ out = (short) (out & ~mask | bits);
}
return out;
}
/**
- *
- * Converts an array of short into an int using the default (little endian, Lsb0) byte and
- * bit ordering.
- *
+ * Converts bytes from an array into a UUID using the default (little-endian, LSB0) byte and bit ordering.
*
- * @param src the short array to convert
- * @param srcPos the position in {@code src}, in short unit, from where to start the
- * conversion
- * @param dstInit initial value of the destination int
- * @param dstPos the position of the lsb, in bits, in the result int
- * @param nShorts the number of shorts to convert
- * @return an int containing the selected bits
- * @throws NullPointerException if {@code src} is {@code null}
- * @throws IllegalArgumentException if {@code (nShorts-1)*16+dstPos >= 32}
- * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nShorts > src.length}
+ * @param src The byte array to convert.
+ * @param srcPos The position in {@code src} where to copy the result from.
+ * @return A UUID.
+ * @throws NullPointerException if {@code src} is {@code null}.
+ * @throws IllegalArgumentException if array does not contain at least 16 bytes beginning with {@code srcPos}.
*/
- public static int shortArrayToInt(final short[] src, final int srcPos, final int dstInit, final int dstPos,
- final int nShorts) {
- if (src.length == 0 && srcPos == 0 || 0 == nShorts) {
- return dstInit;
- }
- if ((nShorts - 1) * 16 + dstPos >= 32) {
- throw new IllegalArgumentException("(nShorts-1)*16+dstPos is greater or equal to than 32");
- }
- int out = dstInit;
- for (int i = 0; i < nShorts; i++) {
- final int shift = i * 16 + dstPos;
- final int bits = (0xffff & src[i + srcPos]) << shift;
- final int mask = 0xffff << shift;
- out = (out & ~mask) | bits;
+ public static UUID byteArrayToUuid(final byte[] src, final int srcPos) {
+ if (src.length - srcPos < 16) {
+ throw new IllegalArgumentException("Need at least 16 bytes for UUID");
}
- return out;
+ return new UUID(byteArrayToLong(src, srcPos, 0, 0, Byte.SIZE), byteArrayToLong(src, srcPos + 8, 0, 0, Byte.SIZE));
}
/**
- *
- * Converts an array of byte into a long using the default (little endian, Lsb0) byte and
- * bit ordering.
- *
+ * Converts a byte into an array of boolean using the default (little-endian, LSB0) byte and bit ordering.
*
- * @param src the byte array to convert
- * @param srcPos the position in {@code src}, in byte unit, from where to start the
- * conversion
- * @param dstInit initial value of the destination long
- * @param dstPos the position of the lsb, in bits, in the result long
- * @param nBytes the number of bytes to convert
- * @return a long containing the selected bits
- * @throws NullPointerException if {@code src} is {@code null}
- * @throws IllegalArgumentException if {@code (nBytes-1)*8+dstPos >= 64}
- * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBytes > src.length}
+ * @param src The byte to convert.
+ * @param srcPos The position in {@code src}, in bits, from where to start the conversion.
+ * @param dst The destination array.
+ * @param dstPos The position in {@code dst} where to copy the result.
+ * @param nBools The number of booleans to copy to {@code dst}, must be smaller or equal to the width of the input (from srcPos to MSB).
+ * @return {@code dst}.
+ * @throws NullPointerException if {@code dst} is {@code null}.
+ * @throws IllegalArgumentException if {@code nBools - 1 + srcPos >= 8}.
+ * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBools > dst.length}.
*/
- public static long byteArrayToLong(final byte[] src, final int srcPos, final long dstInit, final int dstPos,
- final int nBytes) {
- if (src.length == 0 && srcPos == 0 || 0 == nBytes) {
- return dstInit;
+ public static boolean[] byteToBinary(final byte src, final int srcPos, final boolean[] dst, final int dstPos, final int nBools) {
+ if (0 == nBools) {
+ return dst;
}
- if ((nBytes - 1) * 8 + dstPos >= 64) {
- throw new IllegalArgumentException("(nBytes-1)*8+dstPos is greater or equal to than 64");
+ if ((long) nBools - 1 + srcPos >= Byte.SIZE) {
+ throw new IllegalArgumentException("nBools - 1 + srcPos >= 8");
}
- long out = dstInit;
- for (int i = 0; i < nBytes; i++) {
- final int shift = i * 8 + dstPos;
- final long bits = (0xffL & src[i + srcPos]) << shift;
- final long mask = 0xffL << shift;
- out = (out & ~mask) | bits;
+ for (int i = 0; i < nBools; i++) {
+ final int shift = i + srcPos;
+ dst[dstPos + i] = (0x1 & src >> shift) != 0;
}
- return out;
+ return dst;
}
/**
- *
- * Converts an array of byte into an int using the default (little endian, Lsb0) byte and bit
- * ordering.
- *
+ * Converts a byte into an array of char using the default (little-endian, LSB0) byte and bit ordering.
*
- * @param src the byte array to convert
- * @param srcPos the position in {@code src}, in byte unit, from where to start the
- * conversion
- * @param dstInit initial value of the destination int
- * @param dstPos the position of the lsb, in bits, in the result int
- * @param nBytes the number of bytes to convert
- * @return an int containing the selected bits
- * @throws NullPointerException if {@code src} is {@code null}
- * @throws IllegalArgumentException if {@code (nBytes-1)*8+dstPos >= 32}
- * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBytes > src.length}
+ * @param src The byte to convert.
+ * @param srcPos The position in {@code src}, in bits, from where to start the conversion.
+ * @param dstInit The initial value for the result String.
+ * @param dstPos The position in {@code dst} where to copy the result.
+ * @param nHexs The number of chars to copy to {@code dst}, must be smaller or equal to the width of the input (from srcPos to MSB).
+ * @return {@code dst}.
+ * @throws IllegalArgumentException if {@code (nHexs - 1) * 4 + srcPos >= 8}.
+ * @throws StringIndexOutOfBoundsException if {@code dst.init.length() < dstPos}.
*/
- public static int byteArrayToInt(final byte[] src, final int srcPos, final int dstInit, final int dstPos,
- final int nBytes) {
- if (src.length == 0 && srcPos == 0 || 0 == nBytes) {
+ public static String byteToHex(final byte src, final int srcPos, final String dstInit, final int dstPos, final int nHexs) {
+ if (0 == nHexs) {
return dstInit;
}
- if ((nBytes - 1) * 8 + dstPos >= 32) {
- throw new IllegalArgumentException("(nBytes-1)*8+dstPos is greater or equal to than 32");
+ if (((long) nHexs - 1) * 4 + srcPos >= Byte.SIZE) {
+ throw new IllegalArgumentException("(nHexs - 1) * 4 + srcPos >= 8");
}
- int out = dstInit;
- for (int i = 0; i < nBytes; i++) {
- final int shift = i * 8 + dstPos;
- final int bits = (0xff & src[i + srcPos]) << shift;
- final int mask = 0xff << shift;
- out = (out & ~mask) | bits;
+ final StringBuilder sb = new StringBuilder(dstInit);
+ int append = sb.length();
+ for (int i = 0; i < nHexs; i++) {
+ final int shift = i * 4 + srcPos;
+ final int bits = 0xF & src >> shift;
+ if (dstPos + i == append) {
+ ++append;
+ sb.append(intToHexDigit(bits));
+ } else {
+ sb.setCharAt(dstPos + i, intToHexDigit(bits));
+ }
}
- return out;
+ return sb.toString();
}
/**
+ * Converts a hexadecimal digit into binary (represented as boolean array) using the MSB0 bit ordering.
+ *
*
- * Converts an array of byte into a short using the default (little endian, Lsb0) byte and
- * bit ordering.
+ * '1' is converted as follow: (0, 0, 0, 1).
*
*
- * @param src the byte array to convert
- * @param srcPos the position in {@code src}, in byte unit, from where to start the
- * conversion
- * @param dstInit initial value of the destination short
- * @param dstPos the position of the lsb, in bits, in the result short
- * @param nBytes the number of bytes to convert
- * @return a short containing the selected bits
- * @throws NullPointerException if {@code src} is {@code null}
- * @throws IllegalArgumentException if {@code (nBytes-1)*8+dstPos >= 16}
- * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBytes > src.length}
+ * @param hexChar The hexadecimal digit to convert.
+ * @return A boolean array with the binary representation of {@code hexDigit}.
+ * @throws IllegalArgumentException if {@code hexDigit} is not a hexadecimal digit.
*/
- public static short byteArrayToShort(final byte[] src, final int srcPos, final short dstInit, final int dstPos,
- final int nBytes) {
- if (src.length == 0 && srcPos == 0 || 0 == nBytes) {
- return dstInit;
- }
- if ((nBytes - 1) * 8 + dstPos >= 16) {
- throw new IllegalArgumentException("(nBytes-1)*8+dstPos is greater or equal to than 16");
- }
- short out = dstInit;
- for (int i = 0; i < nBytes; i++) {
- final int shift = i * 8 + dstPos;
- final int bits = (0xff & src[i + srcPos]) << shift;
- final int mask = 0xff << shift;
- out = (short) ((out & ~mask) | bits);
+ public static boolean[] hexDigitMsb0ToBinary(final char hexChar) {
+ switch (hexChar) {
+ case '0':
+ return FFFF.clone();
+ case '1':
+ return FFFT.clone();
+ case '2':
+ return FFTF.clone();
+ case '3':
+ return FFTT.clone();
+ case '4':
+ return FTFF.clone();
+ case '5':
+ return FTFT.clone();
+ case '6':
+ return FTTF.clone();
+ case '7':
+ return FTTT.clone();
+ case '8':
+ return TFFF.clone();
+ case '9':
+ return TFFT.clone();
+ case 'a':// fall through
+ case 'A':
+ return TFTF.clone();
+ case 'b':// fall through
+ case 'B':
+ return TFTT.clone();
+ case 'c':// fall through
+ case 'C':
+ return TTFF.clone();
+ case 'd':// fall through
+ case 'D':
+ return TTFT.clone();
+ case 'e':// fall through
+ case 'E':
+ return TTTF.clone();
+ case 'f':// fall through
+ case 'F':
+ return TTTT.clone();
+ default:
+ throw new IllegalArgumentException("Cannot convert '" + hexChar + "' to a hexadecimal digit");
}
- return out;
}
/**
+ * Converts a hexadecimal digit into an int using the MSB0 bit ordering.
+ *
*
- * Converts an array of Char into a long using the default (little endian, Lsb0) byte and
- * bit ordering.
+ * '1' is converted to 8.
*
*
- * @param src the hex string to convert
- * @param srcPos the position in {@code src}, in Char unit, from where to start the
- * conversion
- * @param dstInit initial value of the destination long
- * @param dstPos the position of the lsb, in bits, in the result long
- * @param nHex the number of Chars to convert
- * @return a long containing the selected bits
- * @throws IllegalArgumentException if {@code (nHexs-1)*4+dstPos >= 64}
+ * @param hexChar The hexadecimal digit to convert.
+ * @return An int equals to {@code hexDigit}.
+ * @throws IllegalArgumentException if {@code hexDigit} is not a hexadecimal digit.
*/
- public static long hexToLong(final String src, final int srcPos, final long dstInit, final int dstPos,
- final int nHex) {
- if (0 == nHex) {
- return dstInit;
- }
- if ((nHex - 1) * 4 + dstPos >= 64) {
- throw new IllegalArgumentException("(nHexs-1)*4+dstPos is greater or equal to than 64");
- }
- long out = dstInit;
- for (int i = 0; i < nHex; i++) {
- final int shift = i * 4 + dstPos;
- final long bits = (0xfL & hexDigitToInt(src.charAt(i + srcPos))) << shift;
- final long mask = 0xfL << shift;
- out = (out & ~mask) | bits;
+ public static int hexDigitMsb0ToInt(final char hexChar) {
+ switch (hexChar) {
+ case '0':
+ return 0x0;
+ case '1':
+ return 0x8;
+ case '2':
+ return 0x4;
+ case '3':
+ return 0xC;
+ case '4':
+ return 0x2;
+ case '5':
+ return 0xA;
+ case '6':
+ return 0x6;
+ case '7':
+ return 0xE;
+ case '8':
+ return 0x1;
+ case '9':
+ return 0x9;
+ case 'a':// fall through
+ case 'A':
+ return 0x5;
+ case 'b':// fall through
+ case 'B':
+ return 0xD;
+ case 'c':// fall through
+ case 'C':
+ return 0x3;
+ case 'd':// fall through
+ case 'D':
+ return 0xB;
+ case 'e':// fall through
+ case 'E':
+ return 0x7;
+ case 'f':// fall through
+ case 'F':
+ return 0xF;
+ default:
+ throw new IllegalArgumentException("Cannot convert '" + hexChar + "' to a hexadecimal digit");
}
- return out;
}
/**
+ * Converts a hexadecimal digit into binary (represented as boolean array) using the default (LSB0) bit ordering.
+ *
*
- * Converts an array of Char into an int using the default (little endian, Lsb0) byte and bit
- * ordering.
+ * '1' is converted as follow: (1, 0, 0, 0).
*
*
- * @param src the hex string to convert
- * @param srcPos the position in {@code src}, in Char unit, from where to start the
- * conversion
- * @param dstInit initial value of the destination int
- * @param dstPos the position of the lsb, in bits, in the result int
- * @param nHex the number of Chars to convert
- * @return an int containing the selected bits
- * @throws IllegalArgumentException if {@code (nHexs-1)*4+dstPos >= 32}
+ * @param hexChar The hexadecimal digit to convert.
+ * @return A boolean array with the binary representation of {@code hexDigit}.
+ * @throws IllegalArgumentException if {@code hexDigit} is not a hexadecimal digit.
*/
- public static int hexToInt(final String src, final int srcPos, final int dstInit, final int dstPos, final int nHex) {
- if (0 == nHex) {
- return dstInit;
- }
- if ((nHex - 1) * 4 + dstPos >= 32) {
- throw new IllegalArgumentException("(nHexs-1)*4+dstPos is greater or equal to than 32");
- }
- int out = dstInit;
- for (int i = 0; i < nHex; i++) {
- final int shift = i * 4 + dstPos;
- final int bits = (0xf & hexDigitToInt(src.charAt(i + srcPos))) << shift;
- final int mask = 0xf << shift;
- out = (out & ~mask) | bits;
+ public static boolean[] hexDigitToBinary(final char hexChar) {
+ switch (hexChar) {
+ case '0':
+ return FFFF.clone();
+ case '1':
+ return TFFF.clone();
+ case '2':
+ return FTFF.clone();
+ case '3':
+ return TTFF.clone();
+ case '4':
+ return FFTF.clone();
+ case '5':
+ return TFTF.clone();
+ case '6':
+ return FTTF.clone();
+ case '7':
+ return TTTF.clone();
+ case '8':
+ return FFFT.clone();
+ case '9':
+ return TFFT.clone();
+ case 'a':// fall through
+ case 'A':
+ return FTFT.clone();
+ case 'b':// fall through
+ case 'B':
+ return TTFT.clone();
+ case 'c':// fall through
+ case 'C':
+ return FFTT.clone();
+ case 'd':// fall through
+ case 'D':
+ return TFTT.clone();
+ case 'e':// fall through
+ case 'E':
+ return FTTT.clone();
+ case 'f':// fall through
+ case 'F':
+ return TTTT.clone();
+ default:
+ throw new IllegalArgumentException("Cannot convert '" + hexChar + "' to a hexadecimal digit");
}
- return out;
}
/**
+ * Converts a hexadecimal digit into an int using the default (LSB0) bit ordering.
+ *
*
- * Converts an array of Char into a short using the default (little endian, Lsb0) byte and
- * bit ordering.
+ * '1' is converted to 1.
*
*
- * @param src the hex string to convert
- * @param srcPos the position in {@code src}, in Char unit, from where to start the
- * conversion
- * @param dstInit initial value of the destination short
- * @param dstPos the position of the lsb, in bits, in the result short
- * @param nHex the number of Chars to convert
- * @return a short containing the selected bits
- * @throws IllegalArgumentException if {@code (nHexs-1)*4+dstPos >= 16}
+ * @param hexChar The hexadecimal digit to convert.
+ * @return An int equals to {@code hexDigit}.
+ * @throws IllegalArgumentException if {@code hexDigit} is not a hexadecimal digit.
+ */
+ public static int hexDigitToInt(final char hexChar) {
+ if (!CharUtils.isHex(hexChar)) {
+ throw new IllegalArgumentException("Cannot convert '" + hexChar + "' to a hexadecimal digit");
+ }
+ return Character.digit(hexChar, 16);
+ }
+
+ /**
+ * Converts a hexadecimal string into a byte using the default (little-endian, LSB0) byte and bit ordering.
+ *
+ * @param src The hexadecimal string to convert.
+ * @param srcPos The position in {@code src}, in char unit, from where to start the conversion.
+ * @param dstInit initial value of the destination byte.
+ * @param dstPos The position of the LSB, in bits, in the result byte.
+ * @param nHex The number of Chars to convert.
+ * @return A byte containing the selected bits.
+ * @throws IllegalArgumentException if {@code (nHex-1)*4+dstPos >= 8}.
*/
- public static short hexToShort(final String src, final int srcPos, final short dstInit, final int dstPos,
- final int nHex) {
+ public static byte hexToByte(final String src, final int srcPos, final byte dstInit, final int dstPos, final int nHex) {
if (0 == nHex) {
return dstInit;
}
- if ((nHex - 1) * 4 + dstPos >= 16) {
- throw new IllegalArgumentException("(nHexs-1)*4+dstPos is greater or equal to than 16");
+ if (((long) nHex - 1) * 4 + dstPos >= Byte.SIZE) {
+ throw new IllegalArgumentException("(nHex - 1) * 4 + dstPos >= 8");
}
- short out = dstInit;
+ byte out = dstInit;
for (int i = 0; i < nHex; i++) {
final int shift = i * 4 + dstPos;
final int bits = (0xf & hexDigitToInt(src.charAt(i + srcPos))) << shift;
final int mask = 0xf << shift;
- out = (short) ((out & ~mask) | bits);
+ out = (byte) (out & ~mask | bits);
}
return out;
}
/**
- *
- * Converts an array of Char into a byte using the default (little endian, Lsb0) byte and
- * bit ordering.
- *
+ * Converts an array of char into an int using the default (little-endian, LSB0) byte and bit ordering.
*
- * @param src the hex string to convert
- * @param srcPos the position in {@code src}, in Char unit, from where to start the
- * conversion
- * @param dstInit initial value of the destination byte
- * @param dstPos the position of the lsb, in bits, in the result byte
- * @param nHex the number of Chars to convert
- * @return a byte containing the selected bits
- * @throws IllegalArgumentException if {@code (nHexs-1)*4+dstPos >= 8}
+ * @param src The hexadecimal string to convert.
+ * @param srcPos The position in {@code src}, in char unit, from where to start the conversion.
+ * @param dstInit initial value of the destination int.
+ * @param dstPos The position of the LSB, in bits, in the result int.
+ * @param nHex The number of chars to convert.
+ * @return An int containing the selected bits.
+ * @throws IllegalArgumentException if {@code (nHexs - 1) * 4 + dstPos >= 32}.
*/
- public static byte hexToByte(final String src, final int srcPos, final byte dstInit, final int dstPos,
- final int nHex) {
+ public static int hexToInt(final String src, final int srcPos, final int dstInit, final int dstPos, final int nHex) {
if (0 == nHex) {
return dstInit;
}
- if ((nHex - 1) * 4 + dstPos >= 8) {
- throw new IllegalArgumentException("(nHexs-1)*4+dstPos is greater or equal to than 8");
+ if (((long) nHex - 1) * 4 + dstPos >= Integer.SIZE) {
+ throw new IllegalArgumentException("(nHexs - 1) * 4 + dstPos >= 32");
}
- byte out = dstInit;
+ int out = dstInit;
for (int i = 0; i < nHex; i++) {
final int shift = i * 4 + dstPos;
final int bits = (0xf & hexDigitToInt(src.charAt(i + srcPos))) << shift;
final int mask = 0xf << shift;
- out = (byte) ((out & ~mask) | bits);
+ out = out & ~mask | bits;
}
return out;
}
/**
- *
- * Converts binary (represented as boolean array) into a long using the default (little
- * endian, Lsb0) byte and bit ordering.
- *
+ * Converts an array of char into a long using the default (little-endian, LSB0) byte and bit ordering.
*
- * @param src the binary to convert
- * @param srcPos the position in {@code src}, in boolean unit, from where to start the
- * conversion
- * @param dstInit initial value of the destination long
- * @param dstPos the position of the lsb, in bits, in the result long
- * @param nBools the number of booleans to convert
- * @return a long containing the selected bits
- * @throws NullPointerException if {@code src} is {@code null}
- * @throws IllegalArgumentException if {@code nBools-1+dstPos >= 64}
- * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBools > src.length}
+ * @param src The hexadecimal string to convert.
+ * @param srcPos The position in {@code src}, in char unit, from where to start the conversion.
+ * @param dstInit initial value of the destination long.
+ * @param dstPos The position of the LSB, in bits, in the result long.
+ * @param nHex The number of chars to convert.
+ * @return A long containing the selected bits.
+ * @throws IllegalArgumentException if {@code (nHexs - 1) * 4 + dstPos >= 64}.
*/
- public static long binaryToLong(final boolean[] src, final int srcPos, final long dstInit, final int dstPos,
- final int nBools) {
- if (src.length == 0 && srcPos == 0 || 0 == nBools) {
+ public static long hexToLong(final String src, final int srcPos, final long dstInit, final int dstPos, final int nHex) {
+ if (0 == nHex) {
return dstInit;
}
- if (nBools - 1 + dstPos >= 64) {
- throw new IllegalArgumentException("nBools-1+dstPos is greater or equal to than 64");
+ if (((long) nHex - 1) * 4 + dstPos >= Long.SIZE) {
+ throw new IllegalArgumentException("(nHexs - 1) * 4 + dstPos >= 64");
}
long out = dstInit;
- for (int i = 0; i < nBools; i++) {
- final int shift = i + dstPos;
- final long bits = (src[i + srcPos] ? 1L : 0) << shift;
- final long mask = 0x1L << shift;
- out = (out & ~mask) | bits;
+ for (int i = 0; i < nHex; i++) {
+ final int shift = i * 4 + dstPos;
+ final long bits = (0xfL & hexDigitToInt(src.charAt(i + srcPos))) << shift;
+ final long mask = 0xfL << shift;
+ out = out & ~mask | bits;
}
return out;
}
/**
- *
- * Converts binary (represented as boolean array) into an int using the default (little
- * endian, Lsb0) byte and bit ordering.
- *
+ * Converts an array of char into a short using the default (little-endian, LSB0) byte and bit ordering.
*
- * @param src the binary to convert
- * @param srcPos the position in {@code src}, in boolean unit, from where to start the
- * conversion
- * @param dstInit initial value of the destination int
- * @param dstPos the position of the lsb, in bits, in the result int
- * @param nBools the number of booleans to convert
- * @return an int containing the selected bits
- * @throws NullPointerException if {@code src} is {@code null}
- * @throws IllegalArgumentException if {@code nBools-1+dstPos >= 32}
- * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBools > src.length}
+ * @param src The hexadecimal string to convert.
+ * @param srcPos The position in {@code src}, in char unit, from where to start the conversion.
+ * @param dstInit initial value of the destination short.
+ * @param dstPos The position of the LSB, in bits, in the result short.
+ * @param nHex The number of chars to convert.
+ * @return A short containing the selected bits.
+ * @throws IllegalArgumentException if {@code (nHexs - 1) * 4 + dstPos >= 16}.
*/
- public static int binaryToInt(final boolean[] src, final int srcPos, final int dstInit, final int dstPos,
- final int nBools) {
- if (src.length == 0 && srcPos == 0 || 0 == nBools) {
+ public static short hexToShort(final String src, final int srcPos, final short dstInit, final int dstPos, final int nHex) {
+ if (0 == nHex) {
return dstInit;
}
- if (nBools - 1 + dstPos >= 32) {
- throw new IllegalArgumentException("nBools-1+dstPos is greater or equal to than 32");
+ if (((long) nHex - 1) * 4 + dstPos >= Short.SIZE) {
+ throw new IllegalArgumentException("(nHexs - 1) * 4 + dstPos >= 16");
}
- int out = dstInit;
- for (int i = 0; i < nBools; i++) {
- final int shift = i + dstPos;
- final int bits = (src[i + srcPos] ? 1 : 0) << shift;
- final int mask = 0x1 << shift;
- out = (out & ~mask) | bits;
+ short out = dstInit;
+ for (int i = 0; i < nHex; i++) {
+ final int shift = i * 4 + dstPos;
+ final int bits = (0xf & hexDigitToInt(src.charAt(i + srcPos))) << shift;
+ final int mask = 0xf << shift;
+ out = (short) (out & ~mask | bits);
}
return out;
}
/**
- *
- * Converts binary (represented as boolean array) into a short using the default (little
- * endian, Lsb0) byte and bit ordering.
- *
+ * Converts an array of int into a long using the default (little-endian, LSB0) byte and bit ordering.
*
- * @param src the binary to convert
- * @param srcPos the position in {@code src}, in boolean unit, from where to start the
- * conversion
- * @param dstInit initial value of the destination short
- * @param dstPos the position of the lsb, in bits, in the result short
- * @param nBools the number of booleans to convert
- * @return a short containing the selected bits
- * @throws NullPointerException if {@code src} is {@code null}
- * @throws IllegalArgumentException if {@code nBools-1+dstPos >= 16}
- * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBools > src.length}
+ * @param src The int array to convert.
+ * @param srcPos The position in {@code src}, in int unit, from where to start the conversion.
+ * @param dstInit initial value of the destination long.
+ * @param dstPos The position of the LSB, in bits, in the result long.
+ * @param nInts The number of ints to convert.
+ * @return A long containing the selected bits.
+ * @throws IllegalArgumentException if {@code (nInts - 1) * 32 + dstPos >= 64}.
+ * @throws NullPointerException if {@code src} is {@code null}.
+ * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nInts > src.length}.
*/
- public static short binaryToShort(final boolean[] src, final int srcPos, final short dstInit, final int dstPos,
- final int nBools) {
- if (src.length == 0 && srcPos == 0 || 0 == nBools) {
+ public static long intArrayToLong(final int[] src, final int srcPos, final long dstInit, final int dstPos, final int nInts) {
+ if (src.length == 0 && srcPos == 0 || 0 == nInts) {
return dstInit;
}
- if (nBools - 1 + dstPos >= 16) {
- throw new IllegalArgumentException("nBools-1+dstPos is greater or equal to than 16");
+ if (((long) nInts - 1) * Integer.SIZE + dstPos >= Long.SIZE) {
+ throw new IllegalArgumentException("(nInts - 1) * 32 + dstPos >= 64");
}
- short out = dstInit;
- for (int i = 0; i < nBools; i++) {
- final int shift = i + dstPos;
- final int bits = (src[i + srcPos] ? 1 : 0) << shift;
- final int mask = 0x1 << shift;
- out = (short) ((out & ~mask) | bits);
+ long out = dstInit;
+ for (int i = 0; i < nInts; i++) {
+ final int shift = i * Integer.SIZE + dstPos;
+ final long bits = (0xffffffffL & src[i + srcPos]) << shift;
+ final long mask = 0xffffffffL << shift;
+ out = out & ~mask | bits;
}
return out;
}
/**
- *
- * Converts binary (represented as boolean array) into a byte using the default (little
- * endian, Lsb0) byte and bit ordering.
- *
+ * Converts an int into an array of boolean using the default (little-endian, LSB0) byte and bit ordering.
*
- * @param src the binary to convert
- * @param srcPos the position in {@code src}, in boolean unit, from where to start the
- * conversion
- * @param dstInit initial value of the destination byte
- * @param dstPos the position of the lsb, in bits, in the result byte
- * @param nBools the number of booleans to convert
- * @return a byte containing the selected bits
- * @throws NullPointerException if {@code src} is {@code null}
- * @throws IllegalArgumentException if {@code nBools-1+dstPos >= 8}
- * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBools > src.length}
+ * @param src The int to convert.
+ * @param srcPos The position in {@code src}, in bits, from where to start the conversion.
+ * @param dst The destination array.
+ * @param dstPos The position in {@code dst} where to copy the result.
+ * @param nBools The number of booleans to copy to {@code dst}, must be smaller or equal to the width of the input (from srcPos to MSB).
+ * @return {@code dst}.
+ * @throws NullPointerException if {@code dst} is {@code null}.
+ * @throws IllegalArgumentException if {@code nBools - 1 + srcPos >= 32}.
+ * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBools > dst.length}.
*/
- public static byte binaryToByte(final boolean[] src, final int srcPos, final byte dstInit, final int dstPos,
- final int nBools) {
- if (src.length == 0 && srcPos == 0 || 0 == nBools) {
- return dstInit;
+ public static boolean[] intToBinary(final int src, final int srcPos, final boolean[] dst, final int dstPos, final int nBools) {
+ if (0 == nBools) {
+ return dst;
}
- if (nBools - 1 + dstPos >= 8) {
- throw new IllegalArgumentException("nBools-1+dstPos is greater or equal to than 8");
+ if ((long) nBools - 1 + srcPos >= Integer.SIZE) {
+ throw new IllegalArgumentException("nBools - 1 + srcPos >= 32");
}
- byte out = dstInit;
for (int i = 0; i < nBools; i++) {
- final int shift = i + dstPos;
- final int bits = (src[i + srcPos] ? 1 : 0) << shift;
- final int mask = 0x1 << shift;
- out = (byte) ((out & ~mask) | bits);
+ final int shift = i + srcPos;
+ dst[dstPos + i] = (0x1 & src >> shift) != 0;
}
- return out;
+ return dst;
}
/**
- *
- * Converts a long into an array of int using the default (little endian, Lsb0) byte and bit
- * ordering.
- *
+ * Converts an int into an array of byte using the default (little-endian, LSB0) byte and bit ordering.
*
- * @param src the long to convert
- * @param srcPos the position in {@code src}, in bits, from where to start the conversion
- * @param dst the destination array
- * @param dstPos the position in {@code dst} where to copy the result
- * @param nInts the number of ints to copy to {@code dst}, must be smaller or equal to the
- * width of the input (from srcPos to msb)
- * @return {@code dst}
- * @throws NullPointerException if {@code dst} is {@code null} and {@code nInts > 0}
- * @throws IllegalArgumentException if {@code (nInts-1)*32+srcPos >= 64}
- * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nInts > dst.length}
+ * @param src The int to convert.
+ * @param srcPos The position in {@code src}, in bits, from where to start the conversion.
+ * @param dst The destination array.
+ * @param dstPos The position in {@code dst} where to copy the result.
+ * @param nBytes The number of bytes to copy to {@code dst}, must be smaller or equal to the width of the input (from srcPos to MSB).
+ * @return {@code dst}.
+ * @throws NullPointerException if {@code dst} is {@code null}.
+ * @throws IllegalArgumentException if {@code (nBytes - 1) * 8 + srcPos >= 32}.
+ * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBytes > dst.length}.
*/
- public static int[] longToIntArray(final long src, final int srcPos, final int[] dst, final int dstPos,
- final int nInts) {
- if (0 == nInts) {
+ public static byte[] intToByteArray(final int src, final int srcPos, final byte[] dst, final int dstPos, final int nBytes) {
+ if (0 == nBytes) {
return dst;
}
- if ((nInts - 1) * 32 + srcPos >= 64) {
- throw new IllegalArgumentException("(nInts-1)*32+srcPos is greater or equal to than 64");
+ if (((long) nBytes - 1) * Byte.SIZE + srcPos >= Integer.SIZE) {
+ throw new IllegalArgumentException("(nBytes - 1) * 8 + srcPos >= 32");
}
- for (int i = 0; i < nInts; i++) {
- final int shift = i * 32 + srcPos;
- dst[dstPos + i] = (int) (0xffffffff & (src >> shift));
+ for (int i = 0; i < nBytes; i++) {
+ final int shift = i * Byte.SIZE + srcPos;
+ dst[dstPos + i] = (byte) (0xff & src >> shift);
}
return dst;
}
/**
- *
- * Converts a long into an array of short using the default (little endian, Lsb0) byte and
- * bit ordering.
- *
+ * Converts an int into an array of char using the default (little-endian, LSB0) byte and bit ordering.
*
- * @param src the long to convert
- * @param srcPos the position in {@code src}, in bits, from where to start the conversion
- * @param dst the destination array
- * @param dstPos the position in {@code dst} where to copy the result
- * @param nShorts the number of shorts to copy to {@code dst}, must be smaller or equal to
- * the width of the input (from srcPos to msb)
- * @return {@code dst}
- * @throws NullPointerException if {@code dst} is {@code null}
- * @throws IllegalArgumentException if {@code (nShorts-1)*16+srcPos >= 64}
- * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nShorts > dst.length}
+ * @param src The int to convert.
+ * @param srcPos The position in {@code src}, in bits, from where to start the conversion.
+ * @param dstInit The initial value for the result String.
+ * @param dstPos The position in {@code dst} where to copy the result.
+ * @param nHexs The number of chars to copy to {@code dst}, must be smaller or equal to the width of the input (from srcPos to MSB).
+ * @return {@code dst}.
+ * @throws IllegalArgumentException if {@code (nHexs - 1) * 4 + srcPos >= 32}.
+ * @throws StringIndexOutOfBoundsException if {@code dst.init.length() < dstPos}.
*/
- public static short[] longToShortArray(final long src, final int srcPos, final short[] dst, final int dstPos,
- final int nShorts) {
- if (0 == nShorts) {
- return dst;
+ public static String intToHex(final int src, final int srcPos, final String dstInit, final int dstPos, final int nHexs) {
+ if (0 == nHexs) {
+ return dstInit;
}
- if ((nShorts - 1) * 16 + srcPos >= 64) {
- throw new IllegalArgumentException("(nShorts-1)*16+srcPos is greater or equal to than 64");
+ if (((long) nHexs - 1) * 4 + srcPos >= Integer.SIZE) {
+ throw new IllegalArgumentException("(nHexs - 1) * 4 + srcPos >= 32");
}
- for (int i = 0; i < nShorts; i++) {
- final int shift = i * 16 + srcPos;
- dst[dstPos + i] = (short) (0xffff & (src >> shift));
+ final StringBuilder sb = new StringBuilder(dstInit);
+ int append = sb.length();
+ for (int i = 0; i < nHexs; i++) {
+ final int shift = i * 4 + srcPos;
+ final int bits = 0xF & src >> shift;
+ if (dstPos + i == append) {
+ ++append;
+ sb.append(intToHexDigit(bits));
+ } else {
+ sb.setCharAt(dstPos + i, intToHexDigit(bits));
+ }
}
- return dst;
+ return sb.toString();
}
/**
+ * Converts the 4 LSB of an int to a hexadecimal digit.
+ *
*
- * Converts an int into an array of short using the default (little endian, Lsb0) byte and
- * bit ordering.
+ * 0 returns '0'
+ *
+ *
+ * 1 returns '1'
+ *
+ *
+ * 10 returns 'A' and so on...
*
*
- * @param src the int to convert
- * @param srcPos the position in {@code src}, in bits, from where to start the conversion
- * @param dst the destination array
- * @param dstPos the position in {@code dst} where to copy the result
- * @param nShorts the number of shorts to copy to {@code dst}, must be smaller or equal to
- * the width of the input (from srcPos to msb)
- * @return {@code dst}
- * @throws NullPointerException if {@code dst} is {@code null}
- * @throws IllegalArgumentException if {@code (nShorts-1)*16+srcPos >= 32}
- * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nShorts > dst.length}
+ * @param nibble The 4 bits to convert.
+ * @return A hexadecimal digit representing the 4 LSB of {@code nibble}.
+ * @throws IllegalArgumentException if {@code nibble < 0} or {@code nibble > 15}.
*/
- public static short[] intToShortArray(final int src, final int srcPos, final short[] dst, final int dstPos,
- final int nShorts) {
- if (0 == nShorts) {
- return dst;
- }
- if ((nShorts - 1) * 16 + srcPos >= 32) {
- throw new IllegalArgumentException("(nShorts-1)*16+srcPos is greater or equal to than 32");
- }
- for (int i = 0; i < nShorts; i++) {
- final int shift = i * 16 + srcPos;
- dst[dstPos + i] = (short) (0xffff & (src >> shift));
+ public static char intToHexDigit(final int nibble) {
+ final char c = Character.forDigit(nibble, 16);
+ if (c == Character.MIN_VALUE) {
+ throw new IllegalArgumentException("nibble value not between 0 and 15: " + nibble);
}
- return dst;
+ return c;
}
/**
+ * Converts the 4 LSB of an int to a hexadecimal digit encoded using the MSB0 bit ordering.
+ *
+ *
+ * 0 returns '0'
+ *
+ *
+ * 1 returns '8'
+ *
*
- * Converts a long into an array of byte using the default (little endian, Lsb0) byte and
- * bit ordering.
+ * 10 returns '5' and so on...
*
*
- * @param src the long to convert
- * @param srcPos the position in {@code src}, in bits, from where to start the conversion
- * @param dst the destination array
- * @param dstPos the position in {@code dst} where to copy the result
- * @param nBytes the number of bytes to copy to {@code dst}, must be smaller or equal to the
- * width of the input (from srcPos to msb)
- * @return {@code dst}
- * @throws NullPointerException if {@code dst} is {@code null}
- * @throws IllegalArgumentException if {@code (nBytes-1)*8+srcPos >= 64}
- * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBytes > dst.length}
+ * @param nibble The 4 bits to convert.
+ * @return A hexadecimal digit representing the 4 LSB of {@code nibble}.
+ * @throws IllegalArgumentException if {@code nibble < 0} or {@code nibble > 15}.
*/
- public static byte[] longToByteArray(final long src, final int srcPos, final byte[] dst, final int dstPos,
- final int nBytes) {
- if (0 == nBytes) {
+ public static char intToHexDigitMsb0(final int nibble) {
+ switch (nibble) {
+ case 0x0:
+ return '0';
+ case 0x1:
+ return '8';
+ case 0x2:
+ return '4';
+ case 0x3:
+ return 'c';
+ case 0x4:
+ return '2';
+ case 0x5:
+ return 'a';
+ case 0x6:
+ return '6';
+ case 0x7:
+ return 'e';
+ case 0x8:
+ return '1';
+ case 0x9:
+ return '9';
+ case 0xA:
+ return '5';
+ case 0xB:
+ return 'd';
+ case 0xC:
+ return '3';
+ case 0xD:
+ return 'b';
+ case 0xE:
+ return '7';
+ case 0xF:
+ return 'f';
+ default:
+ throw new IllegalArgumentException("nibble value not between 0 and 15: " + nibble);
+ }
+ }
+
+ /**
+ * Converts an int into an array of short using the default (little-endian, LSB0) byte and bit ordering.
+ *
+ * @param src The int to convert.
+ * @param srcPos The position in {@code src}, in bits, from where to start the conversion.
+ * @param dst The destination array.
+ * @param dstPos The position in {@code dst} where to copy the result.
+ * @param nShorts The number of shorts to copy to {@code dst}, must be smaller or equal to the width of the input (from srcPos to MSB).
+ * @return {@code dst}.
+ * @throws NullPointerException if {@code dst} is {@code null}.
+ * @throws IllegalArgumentException if {@code (nShorts - 1) * 16 + srcPos >= 32}.
+ * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nShorts > dst.length}.
+ */
+ public static short[] intToShortArray(final int src, final int srcPos, final short[] dst, final int dstPos, final int nShorts) {
+ if (0 == nShorts) {
return dst;
}
- if ((nBytes - 1) * 8 + srcPos >= 64) {
- throw new IllegalArgumentException("(nBytes-1)*8+srcPos is greater or equal to than 64");
+ if (((long) nShorts - 1) * Short.SIZE + srcPos >= Integer.SIZE) {
+ throw new IllegalArgumentException("(nShorts - 1) * 16 + srcPos >= 32");
}
- for (int i = 0; i < nBytes; i++) {
- final int shift = i * 8 + srcPos;
- dst[dstPos + i] = (byte) (0xff & (src >> shift));
+ for (int i = 0; i < nShorts; i++) {
+ final int shift = i * Short.SIZE + srcPos;
+ dst[dstPos + i] = (short) (0xffff & src >> shift);
}
return dst;
}
/**
- *
- * Converts an int into an array of byte using the default (little endian, Lsb0) byte and bit
- * ordering.
- *
+ * Converts a long into an array of boolean using the default (little-endian, LSB0) byte and bit ordering.
*
- * @param src the int to convert
- * @param srcPos the position in {@code src}, in bits, from where to start the conversion
- * @param dst the destination array
- * @param dstPos the position in {@code dst} where to copy the result
- * @param nBytes the number of bytes to copy to {@code dst}, must be smaller or equal to the
- * width of the input (from srcPos to msb)
- * @return {@code dst}
- * @throws NullPointerException if {@code dst} is {@code null}
- * @throws IllegalArgumentException if {@code (nBytes-1)*8+srcPos >= 32}
- * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBytes > dst.length}
+ * @param src The long to convert.
+ * @param srcPos The position in {@code src}, in bits, from where to start the conversion.
+ * @param dst The destination array.
+ * @param dstPos The position in {@code dst} where to copy the result.
+ * @param nBools The number of booleans to copy to {@code dst}, must be smaller or equal to the width of the input (from srcPos to MSB).
+ * @return {@code dst}.
+ * @throws NullPointerException if {@code dst} is {@code null}.
+ * @throws IllegalArgumentException if {@code nBools - 1 + srcPos >= 64}.
+ * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBools > dst.length}.
*/
- public static byte[] intToByteArray(final int src, final int srcPos, final byte[] dst, final int dstPos,
- final int nBytes) {
- if (0 == nBytes) {
+ public static boolean[] longToBinary(final long src, final int srcPos, final boolean[] dst, final int dstPos, final int nBools) {
+ if (0 == nBools) {
return dst;
}
- if ((nBytes - 1) * 8 + srcPos >= 32) {
- throw new IllegalArgumentException("(nBytes-1)*8+srcPos is greater or equal to than 32");
+ if ((long) nBools - 1 + srcPos >= Long.SIZE) {
+ throw new IllegalArgumentException("nBools - 1 + srcPos >= 64");
}
- for (int i = 0; i < nBytes; i++) {
- final int shift = i * 8 + srcPos;
- dst[dstPos + i] = (byte) (0xff & (src >> shift));
+ for (int i = 0; i < nBools; i++) {
+ final int shift = i + srcPos;
+ dst[dstPos + i] = (0x1 & src >> shift) != 0;
}
return dst;
}
/**
- *
- * Converts a short into an array of byte using the default (little endian, Lsb0) byte and
- * bit ordering.
- *
+ * Converts a long into an array of byte using the default (little-endian, LSB0) byte and bit ordering.
*
- * @param src the short to convert
- * @param srcPos the position in {@code src}, in bits, from where to start the conversion
- * @param dst the destination array
- * @param dstPos the position in {@code dst} where to copy the result
- * @param nBytes the number of bytes to copy to {@code dst}, must be smaller or equal to the
- * width of the input (from srcPos to msb)
- * @return {@code dst}
- * @throws NullPointerException if {@code dst} is {@code null}
- * @throws IllegalArgumentException if {@code (nBytes-1)*8+srcPos >= 16}
- * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBytes > dst.length}
+ * @param src The long to convert.
+ * @param srcPos The position in {@code src}, in bits, from where to start the conversion.
+ * @param dst The destination array.
+ * @param dstPos The position in {@code dst} where to copy the result.
+ * @param nBytes The number of bytes to copy to {@code dst}, must be smaller or equal to the width of the input (from srcPos to MSB).
+ * @return {@code dst}.
+ * @throws NullPointerException if {@code dst} is {@code null}.
+ * @throws IllegalArgumentException if {@code (nBytes - 1) * 8 + srcPos >= 64}.
+ * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBytes > dst.length}.
*/
- public static byte[] shortToByteArray(final short src, final int srcPos, final byte[] dst, final int dstPos,
- final int nBytes) {
+ public static byte[] longToByteArray(final long src, final int srcPos, final byte[] dst, final int dstPos, final int nBytes) {
if (0 == nBytes) {
return dst;
}
- if ((nBytes - 1) * 8 + srcPos >= 16) {
- throw new IllegalArgumentException("(nBytes-1)*8+srcPos is greater or equal to than 16");
+ if (((long) nBytes - 1) * Byte.SIZE + srcPos >= Long.SIZE) {
+ throw new IllegalArgumentException("(nBytes - 1) * 8 + srcPos >= 64");
}
for (int i = 0; i < nBytes; i++) {
- final int shift = i * 8 + srcPos;
- dst[dstPos + i] = (byte) (0xff & (src >> shift));
+ final int shift = i * Byte.SIZE + srcPos;
+ dst[dstPos + i] = (byte) (0xff & src >> shift);
}
return dst;
}
/**
- *
- * Converts a long into an array of Char using the default (little endian, Lsb0) byte and
- * bit ordering.
- *
+ * Converts a long into an array of char using the default (little-endian, LSB0) byte and bit ordering.
*
- * @param src the long to convert
- * @param srcPos the position in {@code src}, in bits, from where to start the conversion
- * @param dstInit the initial value for the result String
- * @param dstPos the position in {@code dst} where to copy the result
- * @param nHexs the number of Chars to copy to {@code dst}, must be smaller or equal to the
- * width of the input (from srcPos to msb)
- * @return {@code dst}
- * @throws IllegalArgumentException if {@code (nHexs-1)*4+srcPos >= 64}
- * @throws StringIndexOutOfBoundsException if {@code dst.init.length() < dstPos}
+ * @param src The long to convert.
+ * @param srcPos The position in {@code src}, in bits, from where to start the conversion.
+ * @param dstInit The initial value for the result String.
+ * @param dstPos The position in {@code dst} where to copy the result.
+ * @param nHexs The number of chars to copy to {@code dst}, must be smaller or equal to the width of the input (from srcPos to MSB).
+ * @return {@code dst}.
+ * @throws IllegalArgumentException if {@code (nHexs - 1) * 4 + srcPos >= 64}.
+ * @throws StringIndexOutOfBoundsException if {@code dst.init.length() < dstPos}.
*/
- public static String longToHex(final long src, final int srcPos, final String dstInit, final int dstPos,
- final int nHexs) {
+ public static String longToHex(final long src, final int srcPos, final String dstInit, final int dstPos, final int nHexs) {
if (0 == nHexs) {
return dstInit;
}
- if ((nHexs - 1) * 4 + srcPos >= 64) {
- throw new IllegalArgumentException("(nHexs-1)*4+srcPos is greater or equal to than 64");
+ if (((long) nHexs - 1) * 4 + srcPos >= Long.SIZE) {
+ throw new IllegalArgumentException("(nHexs - 1) * 4 + srcPos >= 64");
}
final StringBuilder sb = new StringBuilder(dstInit);
int append = sb.length();
for (int i = 0; i < nHexs; i++) {
final int shift = i * 4 + srcPos;
- final int bits = (int) (0xF & (src >> shift));
+ final int bits = (int) (0xF & src >> shift);
if (dstPos + i == append) {
++append;
sb.append(intToHexDigit(bits));
@@ -1266,275 +1160,228 @@ public static String longToHex(final long src, final int srcPos, final String ds
}
/**
- *
- * Converts an int into an array of Char using the default (little endian, Lsb0) byte and bit
- * ordering.
- *
+ * Converts a long into an array of int using the default (little-endian, LSB0) byte and bit ordering.
*
- * @param src the int to convert
- * @param srcPos the position in {@code src}, in bits, from where to start the conversion
- * @param dstInit the initial value for the result String
- * @param dstPos the position in {@code dst} where to copy the result
- * @param nHexs the number of Chars to copy to {@code dst}, must be smaller or equal to the
- * width of the input (from srcPos to msb)
- * @return {@code dst}
- * @throws IllegalArgumentException if {@code (nHexs-1)*4+srcPos >= 32}
- * @throws StringIndexOutOfBoundsException if {@code dst.init.length() < dstPos}
+ * @param src The long to convert.
+ * @param srcPos The position in {@code src}, in bits, from where to start the conversion.
+ * @param dst The destination array.
+ * @param dstPos The position in {@code dst} where to copy the result.
+ * @param nInts The number of ints to copy to {@code dst}, must be smaller or equal to the width of the input (from srcPos to MSB).
+ * @return {@code dst}.
+ * @throws NullPointerException if {@code dst} is {@code null} and {@code nInts > 0}.
+ * @throws IllegalArgumentException if {@code (nInts - 1) * 32 + srcPos >= 64}.
+ * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nInts > dst.length}.
*/
- public static String intToHex(final int src, final int srcPos, final String dstInit, final int dstPos,
- final int nHexs) {
- if (0 == nHexs) {
- return dstInit;
+ public static int[] longToIntArray(final long src, final int srcPos, final int[] dst, final int dstPos, final int nInts) {
+ if (0 == nInts) {
+ return dst;
}
- if ((nHexs - 1) * 4 + srcPos >= 32) {
- throw new IllegalArgumentException("(nHexs-1)*4+srcPos is greater or equal to than 32");
+ if (((long) nInts - 1) * Integer.SIZE + srcPos >= Long.SIZE) {
+ throw new IllegalArgumentException("(nInts - 1) * 32 + srcPos >= 64");
}
- final StringBuilder sb = new StringBuilder(dstInit);
- int append = sb.length();
- for (int i = 0; i < nHexs; i++) {
- final int shift = i * 4 + srcPos;
- final int bits = 0xF & (src >> shift);
- if (dstPos + i == append) {
- ++append;
- sb.append(intToHexDigit(bits));
- } else {
- sb.setCharAt(dstPos + i, intToHexDigit(bits));
- }
+ for (int i = 0; i < nInts; i++) {
+ final int shift = i * Integer.SIZE + srcPos;
+ dst[dstPos + i] = (int) (0xffffffff & src >> shift);
}
- return sb.toString();
+ return dst;
}
/**
- *
- * Converts a short into an array of Char using the default (little endian, Lsb0) byte and
- * bit ordering.
- *
+ * Converts a long into an array of short using the default (little-endian, LSB0) byte and bit ordering.
*
- * @param src the short to convert
- * @param srcPos the position in {@code src}, in bits, from where to start the conversion
- * @param dstInit the initial value for the result String
- * @param dstPos the position in {@code dst} where to copy the result
- * @param nHexs the number of Chars to copy to {@code dst}, must be smaller or equal to the
- * width of the input (from srcPos to msb)
- * @return {@code dst}
- * @throws IllegalArgumentException if {@code (nHexs-1)*4+srcPos >= 16}
- * @throws StringIndexOutOfBoundsException if {@code dst.init.length() < dstPos}
+ * @param src The long to convert.
+ * @param srcPos The position in {@code src}, in bits, from where to start the conversion.
+ * @param dst The destination array.
+ * @param dstPos The position in {@code dst} where to copy the result.
+ * @param nShorts The number of shorts to copy to {@code dst}, must be smaller or equal to the width of the input (from srcPos to MSB).
+ * @return {@code dst}.
+ * @throws NullPointerException if {@code dst} is {@code null}.
+ * @throws IllegalArgumentException if {@code (nShorts - 1) * 16 + srcPos >= 64}.
+ * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nShorts > dst.length}.
*/
- public static String shortToHex(final short src, final int srcPos, final String dstInit, final int dstPos,
- final int nHexs) {
- if (0 == nHexs) {
- return dstInit;
+ public static short[] longToShortArray(final long src, final int srcPos, final short[] dst, final int dstPos, final int nShorts) {
+ if (0 == nShorts) {
+ return dst;
}
- if ((nHexs - 1) * 4 + srcPos >= 16) {
- throw new IllegalArgumentException("(nHexs-1)*4+srcPos is greater or equal to than 16");
+ if (((long) nShorts - 1) * Short.SIZE + srcPos >= Long.SIZE) {
+ throw new IllegalArgumentException("(nShorts - 1) * 16 + srcPos >= 64");
}
- final StringBuilder sb = new StringBuilder(dstInit);
- int append = sb.length();
- for (int i = 0; i < nHexs; i++) {
- final int shift = i * 4 + srcPos;
- final int bits = 0xF & (src >> shift);
- if (dstPos + i == append) {
- ++append;
- sb.append(intToHexDigit(bits));
- } else {
- sb.setCharAt(dstPos + i, intToHexDigit(bits));
- }
+ for (int i = 0; i < nShorts; i++) {
+ final int shift = i * Short.SIZE + srcPos;
+ dst[dstPos + i] = (short) (0xffff & src >> shift);
}
- return sb.toString();
+ return dst;
}
/**
- *
- * Converts a byte into an array of Char using the default (little endian, Lsb0) byte and
- * bit ordering.
- *
+ * Converts an array of short into an int using the default (little-endian, LSB0) byte and bit ordering.
*
- * @param src the byte to convert
- * @param srcPos the position in {@code src}, in bits, from where to start the conversion
- * @param dstInit the initial value for the result String
- * @param dstPos the position in {@code dst} where to copy the result
- * @param nHexs the number of Chars to copy to {@code dst}, must be smaller or equal to the
- * width of the input (from srcPos to msb)
- * @return {@code dst}
- * @throws IllegalArgumentException if {@code (nHexs-1)*4+srcPos >= 8}
- * @throws StringIndexOutOfBoundsException if {@code dst.init.length() < dstPos}
+ * @param src The short array to convert.
+ * @param srcPos The position in {@code src}, in short unit, from where to start the conversion.
+ * @param dstInit initial value of the destination int.
+ * @param dstPos The position of the LSB, in bits, in the result int.
+ * @param nShorts The number of shorts to convert.
+ * @return An int containing the selected bits.
+ * @throws NullPointerException if {@code src} is {@code null}.
+ * @throws IllegalArgumentException if {@code (nShorts - 1) * 16 + dstPos >= 32}.
+ * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nShorts > src.length}.
*/
- public static String byteToHex(final byte src, final int srcPos, final String dstInit, final int dstPos,
- final int nHexs) {
- if (0 == nHexs) {
+ public static int shortArrayToInt(final short[] src, final int srcPos, final int dstInit, final int dstPos, final int nShorts) {
+ if (src.length == 0 && srcPos == 0 || 0 == nShorts) {
return dstInit;
}
- if ((nHexs - 1) * 4 + srcPos >= 8) {
- throw new IllegalArgumentException("(nHexs-1)*4+srcPos is greater or equal to than 8");
+ if (((long) nShorts - 1) * Short.SIZE + dstPos >= Integer.SIZE) {
+ throw new IllegalArgumentException("(nShorts - 1) * 16 + dstPos >= 32");
}
- final StringBuilder sb = new StringBuilder(dstInit);
- int append = sb.length();
- for (int i = 0; i < nHexs; i++) {
- final int shift = i * 4 + srcPos;
- final int bits = 0xF & (src >> shift);
- if (dstPos + i == append) {
- ++append;
- sb.append(intToHexDigit(bits));
- } else {
- sb.setCharAt(dstPos + i, intToHexDigit(bits));
- }
+ int out = dstInit;
+ for (int i = 0; i < nShorts; i++) {
+ final int shift = i * Short.SIZE + dstPos;
+ final int bits = (0xffff & src[i + srcPos]) << shift;
+ final int mask = 0xffff << shift;
+ out = out & ~mask | bits;
}
- return sb.toString();
+ return out;
}
/**
- *
- * Converts a long into an array of boolean using the default (little endian, Lsb0) byte and
- * bit ordering.
- *
+ * Converts an array of short into a long using the default (little-endian, LSB0) byte and bit ordering.
*
- * @param src the long to convert
- * @param srcPos the position in {@code src}, in bits, from where to start the conversion
- * @param dst the destination array
- * @param dstPos the position in {@code dst} where to copy the result
- * @param nBools the number of booleans to copy to {@code dst}, must be smaller or equal to
- * the width of the input (from srcPos to msb)
- * @return {@code dst}
- * @throws NullPointerException if {@code dst} is {@code null}
- * @throws IllegalArgumentException if {@code nBools-1+srcPos >= 64}
- * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBools > dst.length}
+ * @param src The short array to convert.
+ * @param srcPos The position in {@code src}, in short unit, from where to start the conversion.
+ * @param dstInit initial value of the destination long.
+ * @param dstPos The position of the LSB, in bits, in the result long.
+ * @param nShorts The number of shorts to convert.
+ * @return A long containing the selected bits.
+ * @throws NullPointerException if {@code src} is {@code null}.
+ * @throws IllegalArgumentException if {@code (nShorts - 1) * 16 + dstPos >= 64}.
+ * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nShorts > src.length}.
*/
- public static boolean[] longToBinary(final long src, final int srcPos, final boolean[] dst, final int dstPos,
- final int nBools) {
- if (0 == nBools) {
- return dst;
+ public static long shortArrayToLong(final short[] src, final int srcPos, final long dstInit, final int dstPos, final int nShorts) {
+ if (src.length == 0 && srcPos == 0 || 0 == nShorts) {
+ return dstInit;
}
- if (nBools - 1 + srcPos >= 64) {
- throw new IllegalArgumentException("nBools-1+srcPos is greater or equal to than 64");
+ if (((long) nShorts - 1) * Short.SIZE + dstPos >= Long.SIZE) {
+ throw new IllegalArgumentException("(nShorts - 1) * 16 + dstPos >= 64");
}
- for (int i = 0; i < nBools; i++) {
- final int shift = i + srcPos;
- dst[dstPos + i] = (0x1 & (src >> shift)) != 0;
+ long out = dstInit;
+ for (int i = 0; i < nShorts; i++) {
+ final int shift = i * Short.SIZE + dstPos;
+ final long bits = (0xffffL & src[i + srcPos]) << shift;
+ final long mask = 0xffffL << shift;
+ out = out & ~mask | bits;
}
- return dst;
+ return out;
}
/**
- *
- * Converts an int into an array of boolean using the default (little endian, Lsb0) byte and
- * bit ordering.
- *
+ * Converts a short into an array of boolean using the default (little-endian, LSB0) byte and bit ordering.
*
- * @param src the int to convert
- * @param srcPos the position in {@code src}, in bits, from where to start the conversion
- * @param dst the destination array
- * @param dstPos the position in {@code dst} where to copy the result
- * @param nBools the number of booleans to copy to {@code dst}, must be smaller or equal to
- * the width of the input (from srcPos to msb)
- * @return {@code dst}
- * @throws NullPointerException if {@code dst} is {@code null}
- * @throws IllegalArgumentException if {@code nBools-1+srcPos >= 32}
- * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBools > dst.length}
+ * @param src The short to convert.
+ * @param srcPos The position in {@code src}, in bits, from where to start the conversion.
+ * @param dst The destination array.
+ * @param dstPos The position in {@code dst} where to copy the result.
+ * @param nBools The number of booleans to copy to {@code dst}, must be smaller or equal to the width of the input (from srcPos to MSB).
+ * @return {@code dst}.
+ * @throws NullPointerException if {@code dst} is {@code null}.
+ * @throws IllegalArgumentException if {@code nBools - 1 + srcPos >= 16}.
+ * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBools > dst.length}.
*/
- public static boolean[] intToBinary(final int src, final int srcPos, final boolean[] dst, final int dstPos,
- final int nBools) {
+ public static boolean[] shortToBinary(final short src, final int srcPos, final boolean[] dst, final int dstPos, final int nBools) {
if (0 == nBools) {
return dst;
}
- if (nBools - 1 + srcPos >= 32) {
- throw new IllegalArgumentException("nBools-1+srcPos is greater or equal to than 32");
+ if ((long) nBools - 1 + srcPos >= Short.SIZE) {
+ throw new IllegalArgumentException("nBools - 1 + srcPos >= 16");
}
+ assert nBools - 1 < Short.SIZE - srcPos;
for (int i = 0; i < nBools; i++) {
final int shift = i + srcPos;
- dst[dstPos + i] = (0x1 & (src >> shift)) != 0;
+ dst[dstPos + i] = (0x1 & src >> shift) != 0;
}
return dst;
}
/**
- *
- * Converts a short into an array of boolean using the default (little endian, Lsb0) byte
- * and bit ordering.
- *
+ * Converts a short into an array of byte using the default (little-endian, LSB0) byte and bit ordering.
*
- * @param src the short to convert
- * @param srcPos the position in {@code src}, in bits, from where to start the conversion
- * @param dst the destination array
- * @param dstPos the position in {@code dst} where to copy the result
- * @param nBools the number of booleans to copy to {@code dst}, must be smaller or equal to
- * the width of the input (from srcPos to msb)
- * @return {@code dst}
- * @throws NullPointerException if {@code dst} is {@code null}
- * @throws IllegalArgumentException if {@code nBools-1+srcPos >= 16}
- * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBools > dst.length}
+ * @param src The short to convert.
+ * @param srcPos The position in {@code src}, in bits, from where to start the conversion.
+ * @param dst The destination array.
+ * @param dstPos The position in {@code dst} where to copy the result.
+ * @param nBytes The number of bytes to copy to {@code dst}, must be smaller or equal to the width of the input (from srcPos to MSB).
+ * @return {@code dst}.
+ * @throws NullPointerException if {@code dst} is {@code null}.
+ * @throws IllegalArgumentException if {@code (nBytes - 1) * 8 + srcPos >= 16}.
+ * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBytes > dst.length}.
*/
- public static boolean[] shortToBinary(final short src, final int srcPos, final boolean[] dst, final int dstPos,
- final int nBools) {
- if (0 == nBools) {
+ public static byte[] shortToByteArray(final short src, final int srcPos, final byte[] dst, final int dstPos, final int nBytes) {
+ if (0 == nBytes) {
return dst;
}
- if (nBools - 1 + srcPos >= 16) {
- throw new IllegalArgumentException("nBools-1+srcPos is greater or equal to than 16");
+ if (((long) nBytes - 1) * Byte.SIZE + srcPos >= Short.SIZE) {
+ throw new IllegalArgumentException("(nBytes - 1) * 8 + srcPos >= 16");
}
- assert (nBools - 1) < 16 - srcPos;
- for (int i = 0; i < nBools; i++) {
- final int shift = i + srcPos;
- dst[dstPos + i] = (0x1 & (src >> shift)) != 0;
+ for (int i = 0; i < nBytes; i++) {
+ final int shift = i * Byte.SIZE + srcPos;
+ dst[dstPos + i] = (byte) (0xff & src >> shift);
}
return dst;
}
/**
- *
- * Converts a byte into an array of boolean using the default (little endian, Lsb0) byte and
- * bit ordering.
- *
+ * Converts a short into an array of char using the default (little-endian, LSB0) byte and bit ordering.
*
- * @param src the byte to convert
- * @param srcPos the position in {@code src}, in bits, from where to start the conversion
- * @param dst the destination array
- * @param dstPos the position in {@code dst} where to copy the result
- * @param nBools the number of booleans to copy to {@code dst}, must be smaller or equal to
- * the width of the input (from srcPos to msb)
- * @return {@code dst}
- * @throws NullPointerException if {@code dst} is {@code null}
- * @throws IllegalArgumentException if {@code nBools-1+srcPos >= 8}
- * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBools > dst.length}
+ * @param src The short to convert.
+ * @param srcPos The position in {@code src}, in bits, from where to start the conversion.
+ * @param dstInit The initial value for the result String.
+ * @param dstPos The position in {@code dst} where to copy the result.
+ * @param nHexs The number of chars to copy to {@code dst}, must be smaller or equal to the width of the input (from srcPos to MSB).
+ * @return {@code dst}.
+ * @throws IllegalArgumentException if {@code (nHexs - 1) * 4 + srcPos >= 16}.
+ * @throws StringIndexOutOfBoundsException if {@code dst.init.length() < dstPos}.
*/
- public static boolean[] byteToBinary(final byte src, final int srcPos, final boolean[] dst, final int dstPos,
- final int nBools) {
- if (0 == nBools) {
- return dst;
+ public static String shortToHex(final short src, final int srcPos, final String dstInit, final int dstPos, final int nHexs) {
+ if (0 == nHexs) {
+ return dstInit;
}
- if (nBools - 1 + srcPos >= 8) {
- throw new IllegalArgumentException("nBools-1+srcPos is greater or equal to than 8");
+ if (((long) nHexs - 1) * 4 + srcPos >= Short.SIZE) {
+ throw new IllegalArgumentException("(nHexs - 1) * 4 + srcPos >= 16");
}
- for (int i = 0; i < nBools; i++) {
- final int shift = i + srcPos;
- dst[dstPos + i] = (0x1 & (src >> shift)) != 0;
+ final StringBuilder sb = new StringBuilder(dstInit);
+ int append = sb.length();
+ for (int i = 0; i < nHexs; i++) {
+ final int shift = i * 4 + srcPos;
+ final int bits = 0xF & src >> shift;
+ if (dstPos + i == append) {
+ ++append;
+ sb.append(intToHexDigit(bits));
+ } else {
+ sb.setCharAt(dstPos + i, intToHexDigit(bits));
+ }
}
- return dst;
+ return sb.toString();
}
/**
- *
- * Converts UUID into an array of byte using the default (little endian, Lsb0) byte and bit
- * ordering.
- *
+ * Converts UUID into an array of byte using the default (little-endian, LSB0) byte and bit ordering.
*
- * @param src the UUID to convert
- * @param dst the destination array
- * @param dstPos the position in {@code dst} where to copy the result
- * @param nBytes the number of bytes to copy to {@code dst}, must be smaller or equal to the
- * width of the input (from srcPos to msb)
- * @return {@code dst}
- * @throws NullPointerException if {@code dst} is {@code null}
- * @throws IllegalArgumentException if {@code nBytes > 16}
- * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBytes > dst.length}
+ * @param src The UUID to convert.
+ * @param dst The destination array.
+ * @param dstPos The position in {@code dst} where to copy the result.
+ * @param nBytes The number of bytes to copy to {@code dst}, must be smaller or equal to the width of the input (from srcPos to MSB).
+ * @return {@code dst}.
+ * @throws NullPointerException if {@code dst} is {@code null}.
+ * @throws IllegalArgumentException if {@code nBytes > 16}.
+ * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBytes > dst.length}.
*/
public static byte[] uuidToByteArray(final UUID src, final byte[] dst, final int dstPos, final int nBytes) {
if (0 == nBytes) {
return dst;
}
if (nBytes > 16) {
- throw new IllegalArgumentException("nBytes is greater than 16");
+ throw new IllegalArgumentException("nBytes > 16");
}
- longToByteArray(src.getMostSignificantBits(), 0, dst, dstPos, nBytes > 8 ? 8 : nBytes);
+ longToByteArray(src.getMostSignificantBits(), 0, dst, dstPos, Math.min(nBytes, 8));
if (nBytes >= 8) {
longToByteArray(src.getLeastSignificantBits(), 0, dst, dstPos + 8, nBytes - 8);
}
@@ -1542,22 +1389,12 @@ public static byte[] uuidToByteArray(final UUID src, final byte[] dst, final int
}
/**
- *
- * Converts bytes from an array into a UUID using the default (little endian, Lsb0) byte and
- * bit ordering.
- *
+ * Constructs a new instance.
*
- * @param src the byte array to convert
- * @param srcPos the position in {@code src} where to copy the result from
- * @return a UUID
- * @throws NullPointerException if {@code src} is {@code null}
- * @throws IllegalArgumentException if array does not contain at least 16 bytes beginning
- * with {@code srcPos}
+ * @deprecated Will be removed in 4.0.0.
*/
- public static UUID byteArrayToUuid(final byte[] src, final int srcPos) {
- if (src.length - srcPos < 16) {
- throw new IllegalArgumentException("Need at least 16 bytes for UUID");
- }
- return new UUID(byteArrayToLong(src, srcPos, 0, 0, 8), byteArrayToLong(src, srcPos + 8, 0, 0, 8));
+ @Deprecated
+ public Conversion() {
+ // empty
}
}
diff --git a/src/main/java/org/apache/commons/lang3/DoubleRange.java b/src/main/java/org/apache/commons/lang3/DoubleRange.java
new file mode 100644
index 00000000000..da1185835b3
--- /dev/null
+++ b/src/main/java/org/apache/commons/lang3/DoubleRange.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.lang3;
+
+/**
+ * Specializes {@link NumberRange} for {@link Double}s.
+ *
+ *
+ * This class is not designed to interoperate with other NumberRanges
+ *
+ *
+ * @since 3.13.0
+ */
+public final class DoubleRange extends NumberRange {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Creates a range with the specified minimum and maximum values (both inclusive).
+ *
+ *
+ * The range uses the natural ordering of the elements to determine where values lie in the range.
+ *
+ *
+ *
+ * The arguments may be passed in the order (min, max) or (max,min). The getMinimum and getMaximum methods will return the correct values.
+ *
+ *
+ * @param fromInclusive The first value that defines the edge of the range, inclusive.
+ * @param toInclusive The second value that defines the edge of the range, inclusive.
+ * @return The range object, not null.
+ * @throws IllegalArgumentException if either value is NaN.
+ */
+ public static DoubleRange of(final double fromInclusive, final double toInclusive) {
+ return of(Double.valueOf(fromInclusive), Double.valueOf(toInclusive));
+ }
+
+ /**
+ * Creates a range with the specified minimum and maximum values (both inclusive).
+ *
+ *
+ * The range uses the natural ordering of the elements to determine where values lie in the range.
+ *
+ *
+ *
+ * The arguments may be passed in the order (min, max) or (max,min). The getMinimum and getMaximum methods will return the correct values.
+ *
+ *
+ * @param fromInclusive The first value that defines the edge of the range, inclusive.
+ * @param toInclusive The second value that defines the edge of the range, inclusive.
+ * @return The range object, not null.
+ * @throws NullPointerException if either element is null.
+ * @throws IllegalArgumentException if either element is NaN.
+ */
+ public static DoubleRange of(final Double fromInclusive, final Double toInclusive) {
+ return new DoubleRange(fromInclusive, toInclusive);
+ }
+
+ /**
+ * Creates an instance.
+ *
+ * @param number1 The first element, not null.
+ * @param number2 The second element, not null.
+ * @throws NullPointerException when element1 is null.
+ * @throws NullPointerException when element2 is null.
+ * @throws IllegalArgumentException when element1 or element2 is NaN.
+ */
+ private DoubleRange(final Double number1, final Double number2) {
+ super(number1, number2, null);
+ }
+
+ /**
+ * Fits the given value into this range by returning the given value or, if out of bounds, the range minimum if
+ * below, or the range maximum if above.
+ *
+ *
+ *
+ * @param element The element to test.
+ * @return The minimum, the element, or the maximum depending on the element's location relative to the range.
+ * @since 3.19.0
+ */
+ public double fit(final double element) {
+ return super.fit(element).doubleValue();
+ }
+
+}
diff --git a/src/main/java/org/apache/commons/lang3/EnumUtils.java b/src/main/java/org/apache/commons/lang3/EnumUtils.java
index 75b052a9fcf..a0557f18ecc 100644
--- a/src/main/java/org/apache/commons/lang3/EnumUtils.java
+++ b/src/main/java/org/apache/commons/lang3/EnumUtils.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -20,12 +20,18 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
-import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
+import java.util.function.Function;
+import java.util.function.ToIntFunction;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.apache.commons.lang3.stream.Streams;
/**
- *
Utility library to provide helper methods for Java enums.
+ * Provides methods for Java enums.
*
*
#ThreadSafe#
*
@@ -33,57 +39,58 @@
*/
public class EnumUtils {
- private static final String NULL_ELEMENTS_NOT_PERMITTED = "null elements not permitted";
private static final String CANNOT_STORE_S_S_VALUES_IN_S_BITS = "Cannot store %s %s values in %s bits";
- private static final String S_DOES_NOT_SEEM_TO_BE_AN_ENUM_TYPE = "%s does not seem to be an Enum type";
private static final String ENUM_CLASS_MUST_BE_DEFINED = "EnumClass must be defined.";
+ private static final String NULL_ELEMENTS_NOT_PERMITTED = "null elements not permitted";
+ private static final String S_DOES_NOT_SEEM_TO_BE_AN_ENUM_TYPE = "%s does not seem to be an Enum type";
/**
* Validate {@code enumClass}.
- * @param the type of the enumeration
- * @param enumClass to check
- * @return {@code enumClass}
- * @throws NullPointerException if {@code enumClass} is {@code null}
- * @throws IllegalArgumentException if {@code enumClass} is not an enum class
+ *
+ * @param The type of the enumeration.
+ * @param enumClass to check.
+ * @return {@code enumClass}.
+ * @throws NullPointerException if {@code enumClass} is {@code null}.
+ * @throws IllegalArgumentException if {@code enumClass} is not an enum class.
* @since 3.2
*/
private static > Class asEnum(final Class enumClass) {
- Validate.notNull(enumClass, ENUM_CLASS_MUST_BE_DEFINED);
+ Objects.requireNonNull(enumClass, ENUM_CLASS_MUST_BE_DEFINED);
Validate.isTrue(enumClass.isEnum(), S_DOES_NOT_SEEM_TO_BE_AN_ENUM_TYPE, enumClass);
return enumClass;
}
/**
* Validate that {@code enumClass} is compatible with representation in a {@code long}.
- * @param the type of the enumeration
- * @param enumClass to check
- * @return {@code enumClass}
- * @throws NullPointerException if {@code enumClass} is {@code null}
- * @throws IllegalArgumentException if {@code enumClass} is not an enum class or has more than 64 values
+ *
+ * @param The type of the enumeration.
+ * @param enumClass to check.
+ * @return {@code enumClass}.
+ * @throws NullPointerException if {@code enumClass} is {@code null}.
+ * @throws IllegalArgumentException if {@code enumClass} is not an enum class or has more than 64 values.
* @since 3.0.1
*/
private static > Class checkBitVectorable(final Class enumClass) {
final E[] constants = asEnum(enumClass).getEnumConstants();
- Validate.isTrue(constants.length <= Long.SIZE, CANNOT_STORE_S_S_VALUES_IN_S_BITS,
- Integer.valueOf(constants.length), enumClass.getSimpleName(), Integer.valueOf(Long.SIZE));
-
+ Validate.isTrue(constants.length <= Long.SIZE, CANNOT_STORE_S_S_VALUES_IN_S_BITS, Integer.valueOf(constants.length), enumClass.getSimpleName(),
+ Integer.valueOf(Long.SIZE));
return enumClass;
}
/**
- *
Creates a long bit vector representation of the given array of Enum values.
+ * Creates a long bit vector representation of the given array of Enum values.
*
*
This generates a value that is usable by {@link EnumUtils#processBitVector}.
*
*
Do not use this method if you have more than 64 values in your Enum, as this
* would create a value greater than a long can hold.
*
- * @param enumClass the class of the enum we are working with, not {@code null}
- * @param values the values we want to convert, not {@code null}
- * @param the type of the enumeration
- * @return a long whose value provides a binary representation of the given set of enum values.
- * @throws NullPointerException if {@code enumClass} or {@code values} is {@code null}
- * @throws IllegalArgumentException if {@code enumClass} is not an enum class or has more than 64 values
+ * @param enumClass The class of the enum we are working with, not {@code null}.
+ * @param values The values we want to convert, not {@code null}.
+ * @param the type of the enumeration.
+ * @return A long whose value provides a binary representation of the given set of enum values.
+ * @throws NullPointerException if {@code enumClass} or {@code values} is {@code null}.
+ * @throws IllegalArgumentException if {@code enumClass} is not an enum class or has more than 64 values.
* @since 3.0.1
* @see #generateBitVectors(Class, Iterable)
*/
@@ -94,48 +101,48 @@ public static > long generateBitVector(final Class enumClas
}
/**
- *
Creates a long bit vector representation of the given subset of an Enum.
+ * Creates a long bit vector representation of the given subset of an Enum.
*
*
This generates a value that is usable by {@link EnumUtils#processBitVector}.
*
*
Do not use this method if you have more than 64 values in your Enum, as this
* would create a value greater than a long can hold.
*
- * @param enumClass the class of the enum we are working with, not {@code null}
- * @param values the values we want to convert, not {@code null}, neither containing {@code null}
- * @param the type of the enumeration
- * @return a long whose value provides a binary representation of the given set of enum values.
- * @throws NullPointerException if {@code enumClass} or {@code values} is {@code null}
+ * @param enumClass The class of the enum we are working with, not {@code null}.
+ * @param values The values we want to convert, not {@code null}, neither containing {@code null}.
+ * @param the type of the enumeration.
+ * @return A long whose value provides a binary representation of the given set of enum values.
+ * @throws NullPointerException if {@code enumClass} or {@code values} is {@code null}.
* @throws IllegalArgumentException if {@code enumClass} is not an enum class or has more than 64 values,
- * or if any {@code values} {@code null}
+ * or if any {@code values} {@code null}.
* @since 3.0.1
* @see #generateBitVectors(Class, Iterable)
*/
public static > long generateBitVector(final Class enumClass, final Iterable extends E> values) {
checkBitVectorable(enumClass);
- Validate.notNull(values);
+ Objects.requireNonNull(values, "values");
long total = 0;
for (final E constant : values) {
- Validate.isTrue(constant != null, NULL_ELEMENTS_NOT_PERMITTED);
+ Objects.requireNonNull(constant, NULL_ELEMENTS_NOT_PERMITTED);
total |= 1L << constant.ordinal();
}
return total;
}
/**
- *
Creates a bit vector representation of the given subset of an Enum using as many {@code long}s as needed.
+ * Creates a bit vector representation of the given subset of an Enum using as many {@code long}s as needed.
*
*
This generates a value that is usable by {@link EnumUtils#processBitVectors}.
*
*
Use this method if you have more than 64 values in your Enum.
*
- * @param enumClass the class of the enum we are working with, not {@code null}
- * @param values the values we want to convert, not {@code null}, neither containing {@code null}
- * @param the type of the enumeration
- * @return a long[] whose values provide a binary representation of the given set of enum values
- * with least significant digits rightmost.
- * @throws NullPointerException if {@code enumClass} or {@code values} is {@code null}
- * @throws IllegalArgumentException if {@code enumClass} is not an enum class, or if any {@code values} {@code null}
+ * @param enumClass The class of the enum we are working with, not {@code null}.
+ * @param values The values we want to convert, not {@code null}, neither containing {@code null}.
+ * @param the type of the enumeration.
+ * @return A long[] whose values provide a binary representation of the given set of enum values
+ * with the least significant digits rightmost.
+ * @throws NullPointerException if {@code enumClass} or {@code values} is {@code null}.
+ * @throws IllegalArgumentException if {@code enumClass} is not an enum class, or if any {@code values} {@code null}.
* @since 3.2
*/
@SafeVarargs
@@ -146,93 +153,90 @@ public static > long[] generateBitVectors(final Class enumC
Collections.addAll(condensed, values);
final long[] result = new long[(enumClass.getEnumConstants().length - 1) / Long.SIZE + 1];
for (final E value : condensed) {
- result[value.ordinal() / Long.SIZE] |= 1L << (value.ordinal() % Long.SIZE);
+ result[value.ordinal() / Long.SIZE] |= 1L << value.ordinal() % Long.SIZE;
}
ArrayUtils.reverse(result);
return result;
}
/**
- *
Creates a bit vector representation of the given subset of an Enum using as many {@code long}s as needed.
+ * Creates a bit vector representation of the given subset of an Enum using as many {@code long}s as needed.
*
*
This generates a value that is usable by {@link EnumUtils#processBitVectors}.
*
*
Use this method if you have more than 64 values in your Enum.
*
- * @param enumClass the class of the enum we are working with, not {@code null}
- * @param values the values we want to convert, not {@code null}, neither containing {@code null}
- * @param the type of the enumeration
- * @return a long[] whose values provide a binary representation of the given set of enum values
- * with least significant digits rightmost.
- * @throws NullPointerException if {@code enumClass} or {@code values} is {@code null}
- * @throws IllegalArgumentException if {@code enumClass} is not an enum class, or if any {@code values} {@code null}
+ * @param enumClass The class of the enum we are working with, not {@code null}.
+ * @param values The values we want to convert, not {@code null}, neither containing {@code null}.
+ * @param the type of the enumeration.
+ * @return A long[] whose values provide a binary representation of the given set of enum values
+ * with the least significant digits rightmost.
+ * @throws NullPointerException if {@code enumClass} or {@code values} is {@code null}.
+ * @throws IllegalArgumentException if {@code enumClass} is not an enum class, or if any {@code values} {@code null}.
* @since 3.2
*/
public static > long[] generateBitVectors(final Class enumClass, final Iterable extends E> values) {
asEnum(enumClass);
- Validate.notNull(values);
+ Objects.requireNonNull(values, "values");
final EnumSet condensed = EnumSet.noneOf(enumClass);
- for (final E constant : values) {
- Validate.isTrue(constant != null, NULL_ELEMENTS_NOT_PERMITTED);
- condensed.add(constant);
- }
+ values.forEach(constant -> condensed.add(Objects.requireNonNull(constant, NULL_ELEMENTS_NOT_PERMITTED)));
final long[] result = new long[(enumClass.getEnumConstants().length - 1) / Long.SIZE + 1];
for (final E value : condensed) {
- result[value.ordinal() / Long.SIZE] |= 1L << (value.ordinal() % Long.SIZE);
+ result[value.ordinal() / Long.SIZE] |= 1L << value.ordinal() % Long.SIZE;
}
ArrayUtils.reverse(result);
return result;
}
/**
- *
Gets the enum for the class, returning {@code null} if not found.
+ * Gets the enum for the class, returning {@code null} if not found.
*
*
This method differs from {@link Enum#valueOf} in that it does not throw an exception
* for an invalid enum name.
*
- * @param the type of the enumeration
- * @param enumClass the class of the enum to query, not null
- * @param enumName the enum name, null returns null
- * @return the enum, null if not found
+ * @param The type of the enumeration.
+ * @param enumClass The class of the enum to query, not null.
+ * @param enumName The enum name, null returns null.
+ * @return The enum, null if not found.
*/
public static > E getEnum(final Class enumClass, final String enumName) {
return getEnum(enumClass, enumName, null);
}
/**
- *
Gets the enum for the class, returning {@code defaultEnum} if not found.
+ * Gets the enum for the class, returning {@code defaultEnum} if not found.
*
*
This method differs from {@link Enum#valueOf} in that it does not throw an exception
* for an invalid enum name.
*
- * @param the type of the enumeration
- * @param enumClass the class of the enum to query, not null
- * @param enumName the enum name, null returns default enum
- * @param defaultEnum the default enum
- * @return the enum, default enum if not found
+ * @param The type of the enumeration.
+ * @param enumClass The class of the enum to query, null returns default enum.
+ * @param enumName The enum name, null returns default enum.
+ * @param defaultEnum The default enum.
+ * @return The enum, default enum if not found.
* @since 3.10
*/
public static > E getEnum(final Class enumClass, final String enumName, final E defaultEnum) {
- if (enumName == null) {
+ if (enumClass == null || enumName == null) {
return defaultEnum;
}
try {
return Enum.valueOf(enumClass, enumName);
- } catch (final IllegalArgumentException ex) {
+ } catch (final IllegalArgumentException e) {
return defaultEnum;
}
}
/**
- *
Gets the enum for the class, returning {@code null} if not found.
+ * Gets the enum for the class, returning {@code null} if not found.
*
*
This method differs from {@link Enum#valueOf} in that it does not throw an exception
* for an invalid enum name and performs case insensitive matching of the name.
*
- * @param the type of the enumeration
- * @param enumClass the class of the enum to query, not null
- * @param enumName the enum name, null returns null
- * @return the enum, null if not found
+ * @param the type of the enumeration.
+ * @param enumClass The class of the enum to query, may be null.
+ * @param enumName The enum name, null returns null.
+ * @return The enum, null if not found.
* @since 3.8
*/
public static > E getEnumIgnoreCase(final Class enumClass, final String enumName) {
@@ -240,86 +244,165 @@ public static > E getEnumIgnoreCase(final Class enumClass,
}
/**
- *
Gets the enum for the class, returning {@code defaultEnum} if not found.
+ * Gets the enum for the class, returning {@code defaultEnum} if not found.
*
*
This method differs from {@link Enum#valueOf} in that it does not throw an exception
* for an invalid enum name and performs case insensitive matching of the name.
*
- * @param the type of the enumeration
- * @param enumClass the class of the enum to query, not null
- * @param enumName the enum name, null returns default enum
- * @param defaultEnum the default enum
- * @return the enum, default enum if not found
+ * @param the type of the enumeration.
+ * @param enumClass The class of the enum to query, null returns default enum.
+ * @param enumName The enum name, null returns default enum.
+ * @param defaultEnum The default enum.
+ * @return The enum, default enum if not found.
* @since 3.10
*/
- public static > E getEnumIgnoreCase(final Class enumClass, final String enumName, final E defaultEnum) {
- if (enumName == null || !enumClass.isEnum()) {
- return defaultEnum;
- }
- for (final E each : enumClass.getEnumConstants()) {
- if (each.name().equalsIgnoreCase(enumName)) {
- return each;
- }
- }
- return defaultEnum;
+ public static > E getEnumIgnoreCase(final Class enumClass, final String enumName,
+ final E defaultEnum) {
+ return getFirstEnumIgnoreCase(enumClass, enumName, Enum::name, defaultEnum);
}
/**
- *
Gets the {@code List} of enums.
+ * Gets the {@link List} of enums.
*
*
This method is useful when you need a list of enums rather than an array.
*
- * @param the type of the enumeration
- * @param enumClass the class of the enum to query, not null
- * @return the modifiable list of enums, never null
+ * @param The type of the enumeration.
+ * @param enumClass The class of the enum to query, not null.
+ * @return The modifiable list of enums, never null.
*/
public static > List getEnumList(final Class enumClass) {
return new ArrayList<>(Arrays.asList(enumClass.getEnumConstants()));
}
/**
- *
Gets the {@code Map} of enums by name.
+ * Gets the {@link Map} of enums by name.
*
*
This method is useful when you need a map of enums by name.
*
- * @param the type of the enumeration
- * @param enumClass the class of the enum to query, not null
- * @return the modifiable map of enum names to enums, never null
+ * @param The type of the enumeration.
+ * @param enumClass The class of the enum to query, not null.
+ * @return The modifiable map of enum names to enums, never null.
*/
public static > Map getEnumMap(final Class enumClass) {
- final Map map = new LinkedHashMap<>();
- for (final E e: enumClass.getEnumConstants()) {
- map.put(e.name(), e);
+ return getEnumMap(enumClass, E::name);
+ }
+
+ /**
+ * Gets the {@link Map} of enums by name.
+ *
+ *
+ * This method is useful when you need a map of enums by name.
+ *
+ *
+ * @param the type of enumeration.
+ * @param the type of the map key.
+ * @param enumClass The class of the enum to query, not null.
+ * @param keyFunction The function to query for the key, not null.
+ * @return The modifiable map of enums, never null.
+ * @since 3.13.0
+ */
+ public static , K> Map getEnumMap(final Class enumClass, final Function keyFunction) {
+ return stream(enumClass).collect(Collectors.toMap(keyFunction::apply, Function.identity()));
+ }
+
+ /**
+ * Gets the enum for the class in a system property, returning {@code defaultEnum} if not found.
+ *
+ *
+ * This method differs from {@link Enum#valueOf} in that it does not throw an exception for an invalid enum name.
+ *
+ *
+ * If a {@link SecurityException} is caught, the return value is {@code null}.
+ *
+ *
+ * @param the type of the enumeration.
+ * @param enumClass The class of the enum to query, not null.
+ * @param propName The system property key for the enum name, null returns default enum.
+ * @param defaultEnum The default enum.
+ * @return The enum, default enum if not found.
+ * @since 3.13.0
+ */
+ public static > E getEnumSystemProperty(final Class enumClass, final String propName, final E defaultEnum) {
+ return getEnum(enumClass, SystemProperties.getProperty(propName), defaultEnum);
+ }
+
+ /**
+ * Gets the enum for the class and value, returning {@code defaultEnum} if not found.
+ *
+ *
+ * This method differs from {@link Enum#valueOf} in that it does not throw an exception for an invalid enum name and performs case insensitive matching of
+ * the name.
+ *
+ *
+ * @param the type of the enumeration.
+ * @param enumClass The class of the enum to query, not null.
+ * @param value The enum name, null returns default enum.
+ * @param toIntFunction The function that gets an int for an enum for comparison to {@code value}.
+ * @param defaultEnum The default enum.
+ * @return An enum, default enum if not found.
+ * @since 3.18.0
+ */
+ public static > E getFirstEnum(final Class enumClass, final int value, final ToIntFunction toIntFunction, final E defaultEnum) {
+ if (!isEnum(enumClass)) {
+ return defaultEnum;
+ }
+ return stream(enumClass).filter(e -> value == toIntFunction.applyAsInt(e)).findFirst().orElse(defaultEnum);
+ }
+
+ /**
+ * Gets the enum for the class, returning {@code defaultEnum} if not found.
+ *
+ *
This method differs from {@link Enum#valueOf} in that it does not throw an exception
+ * for an invalid enum name and performs case insensitive matching of the name.
+ *
+ * @param the type of the enumeration.
+ * @param enumClass The class of the enum to query, null returns default enum.
+ * @param enumName The enum name, null returns default enum.
+ * @param stringFunction The function that gets the string for an enum for comparison to {@code enumName}.
+ * @param defaultEnum The default enum.
+ * @return An enum, default enum if not found.
+ * @since 3.13.0
+ */
+ public static > E getFirstEnumIgnoreCase(final Class enumClass, final String enumName, final Function stringFunction,
+ final E defaultEnum) {
+ if (enumName == null) {
+ return defaultEnum;
}
- return map;
+ return stream(enumClass).filter(e -> enumName.equalsIgnoreCase(stringFunction.apply(e))).findFirst().orElse(defaultEnum);
+ }
+
+ private static > boolean isEnum(final Class enumClass) {
+ return enumClass != null && enumClass.isEnum();
}
/**
- *
Checks if the specified name is a valid enum for the class.
+ * Checks if the specified name is a valid enum for the class.
*
- *
This method differs from {@link Enum#valueOf} in that checks if the name is
- * a valid enum without needing to catch the exception.
+ *
+ * This method differs from {@link Enum#valueOf} in that it checks if the name is a valid enum without needing to catch the exception.
+ *
*
- * @param the type of the enumeration
- * @param enumClass the class of the enum to query, not null
- * @param enumName the enum name, null returns false
- * @return true if the enum name is valid, otherwise false
+ * @param the type of the enumeration.
+ * @param enumClass The class of the enum to query, null returns false.
+ * @param enumName The enum name, null returns false.
+ * @return true if the enum name is valid, otherwise false.
*/
public static > boolean isValidEnum(final Class enumClass, final String enumName) {
return getEnum(enumClass, enumName) != null;
}
/**
- *
Checks if the specified name is a valid enum for the class.
+ * Checks if the specified name is a valid enum for the class.
*
- *
This method differs from {@link Enum#valueOf} in that checks if the name is
- * a valid enum without needing to catch the exception
- * and performs case insensitive matching of the name.
+ *
+ * This method differs from {@link Enum#valueOf} in that it checks if the name is a valid enum without needing to catch the exception and performs case
+ * insensitive matching of the name.
+ *
*
- * @param the type of the enumeration
- * @param enumClass the class of the enum to query, not null
- * @param enumName the enum name, null returns false
- * @return true if the enum name is valid, otherwise false
+ * @param the type of the enumeration.
+ * @param enumClass The class of the enum to query, null returns false.
+ * @param enumName The enum name, null returns false.
+ * @return true if the enum name is valid, otherwise false.
* @since 3.8
*/
public static > boolean isValidEnumIgnoreCase(final Class enumClass, final String enumName) {
@@ -327,53 +410,71 @@ public static > boolean isValidEnumIgnoreCase(final Class e
}
/**
- *
Convert a long value created by {@link EnumUtils#generateBitVector} into the set of
- * enum values that it represents.
+ * Convert a long value created by {@link EnumUtils#generateBitVector} into the set of
+ * enum values that it represents.
*
*
If you store this value, beware any changes to the enum that would affect ordinal values.
- * @param enumClass the class of the enum we are working with, not {@code null}
- * @param value the long value representation of a set of enum values
- * @param the type of the enumeration
- * @return a set of enum values
- * @throws NullPointerException if {@code enumClass} is {@code null}
- * @throws IllegalArgumentException if {@code enumClass} is not an enum class or has more than 64 values
+ *
+ * @param enumClass The class of the enum we are working with, not {@code null}.
+ * @param value The long value representation of a set of enum values.
+ * @param the type of the enumeration.
+ * @return A set of enum values.
+ * @throws NullPointerException if {@code enumClass} is {@code null}.
+ * @throws IllegalArgumentException if {@code enumClass} is not an enum class or has more than 64 values.
* @since 3.0.1
*/
public static > EnumSet processBitVector(final Class enumClass, final long value) {
- checkBitVectorable(enumClass).getEnumConstants();
- return processBitVectors(enumClass, value);
+ return processBitVectors(checkBitVectorable(enumClass), value);
}
/**
- *
Convert a {@code long[]} created by {@link EnumUtils#generateBitVectors} into the set of
- * enum values that it represents.
+ * Convert a {@code long[]} created by {@link EnumUtils#generateBitVectors} into the set of
+ * enum values that it represents.
*
*
If you store this value, beware any changes to the enum that would affect ordinal values.
- * @param enumClass the class of the enum we are working with, not {@code null}
- * @param values the long[] bearing the representation of a set of enum values, least significant digits rightmost, not {@code null}
- * @param the type of the enumeration
- * @return a set of enum values
- * @throws NullPointerException if {@code enumClass} is {@code null}
- * @throws IllegalArgumentException if {@code enumClass} is not an enum class
+ *
+ * @param enumClass The class of the enum we are working with, not {@code null}.
+ * @param values The long[] bearing the representation of a set of enum values, the least significant digits rightmost, not {@code null}.
+ * @param the type of the enumeration.
+ * @return A set of enum values.
+ * @throws NullPointerException if {@code enumClass} is {@code null}.
+ * @throws IllegalArgumentException if {@code enumClass} is not an enum class.
* @since 3.2
*/
public static > EnumSet processBitVectors(final Class enumClass, final long... values) {
final EnumSet results = EnumSet.noneOf(asEnum(enumClass));
- final long[] lvalues = ArrayUtils.clone(Validate.notNull(values));
+ final long[] lvalues = ArrayUtils.clone(Objects.requireNonNull(values, "values"));
ArrayUtils.reverse(lvalues);
- for (final E constant : enumClass.getEnumConstants()) {
+ stream(enumClass).forEach(constant -> {
final int block = constant.ordinal() / Long.SIZE;
- if (block < lvalues.length && (lvalues[block] & 1L << (constant.ordinal() % Long.SIZE)) != 0) {
+ if (block < lvalues.length && (lvalues[block] & 1L << constant.ordinal() % Long.SIZE) != 0) {
results.add(constant);
}
- }
+ });
return results;
}
+ /**
+ * Returns a sequential ordered stream whose elements are the given class' enum values.
+ *
+ * @param the type of stream elements.
+ * @param clazz The class containing the enum values, may be null.
+ * @return The new stream, empty of {@code clazz} is null.
+ * @since 3.18.0
+ * @see Class#getEnumConstants()
+ */
+ public static Stream stream(final Class clazz) {
+ return clazz != null ? Streams.of(clazz.getEnumConstants()) : Stream.empty();
+ }
+
/**
* This constructor is public to permit tools that require a JavaBean
* instance to operate.
+ *
+ * @deprecated TODO Make private in 4.0.
*/
+ @Deprecated
public EnumUtils() {
+ // empty
}
}
diff --git a/src/main/java/org/apache/commons/lang3/Functions.java b/src/main/java/org/apache/commons/lang3/Functions.java
index ef9c45d909b..12325bd4c98 100644
--- a/src/main/java/org/apache/commons/lang3/Functions.java
+++ b/src/main/java/org/apache/commons/lang3/Functions.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -19,6 +19,7 @@
import java.io.IOException;
import java.io.UncheckedIOException;
import java.lang.reflect.UndeclaredThrowableException;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Objects;
import java.util.concurrent.Callable;
@@ -32,533 +33,634 @@
import java.util.stream.Stream;
import org.apache.commons.lang3.Streams.FailableStream;
-
-
-/** This class provides utility functions, and classes for working with the
- * {@code java.util.function} package, or more generally, with Java 8
- * lambdas.
- * More specifically, it attempts to address the fact that lambdas are supposed
- * not to throw Exceptions, at least not checked Exceptions, aka instances of
- * {@link Exception}. This enforces the use of constructs like
+import org.apache.commons.lang3.exception.ExceptionUtils;
+import org.apache.commons.lang3.function.Failable;
+import org.apache.commons.lang3.function.FailableBooleanSupplier;
+
+/**
+ * This class provides utility functions, and classes for working with the {@code java.util.function} package, or more
+ * generally, with Java 8 lambdas. More specifically, it attempts to address the fact that lambdas are supposed not to
+ * throw Exceptions, at least not checked Exceptions, AKA instances of {@link Exception}. This enforces the use of
+ * constructs like:
+ *
*
- * By replacing a {@link java.util.function.Consumer Consumer<O>} with a
- * {@link FailableConsumer FailableConsumer<O,? extends Throwable>}, this can be
- * written like follows:
+ * {@code
+ * Consumer consumer = m -> {
+ * try {
+ * m.invoke(o, args);
+ * } catch (Throwable t) {
+ * throw Functions.rethrow(t);
+ * }
+ * };
+ * }
+ *
+ *
+ * By replacing a {@link java.util.function.Consumer Consumer<O>} with a {@link FailableConsumer
+ * FailableConsumer<O,? extends Throwable>}, this can be written like follows:
+ *
- * Obviously, the second version is much more concise and the spirit of
- * Lambda expressions is met better than the second version.
+ * {@code
+ * Functions.accept((m) -> m.invoke(o,args));
+ * }
+ *
+ *
+ * Obviously, the second version is much more concise and the spirit of Lambda expressions is met better than the second
+ * version.
+ *
+ *
+ * @since 3.9
+ * @deprecated Use {@link org.apache.commons.lang3.function.Failable}.
*/
+@Deprecated
public class Functions {
+ /**
+ * A functional interface like {@link BiConsumer} that declares a {@link Throwable}.
+ *
+ *
TODO for 4.0: Move to org.apache.commons.lang3.function.
+ *
+ * @param Consumed type 1.
+ * @param Consumed type 2.
+ * @param Thrown exception.
+ * @deprecated Use {@link org.apache.commons.lang3.function.FailableBiConsumer}.
+ */
+ @Deprecated
@FunctionalInterface
- public interface FailableRunnable {
+ public interface FailableBiConsumer {
+
/**
- * Runs the function.
- * @throws T if the function fails
+ * Accepts the consumer.
+ *
+ * @param object1 The first parameter for the consumable to accept
+ * @param object2 The second parameter for the consumable to accept
+ * @throws T Thrown when the consumer fails.
*/
- void run() throws T;
+ void accept(O1 object1, O2 object2) throws T;
}
+ /**
+ * A functional interface like {@link BiFunction} that declares a {@link Throwable}.
+ *
+ *
TODO for 4.0: Move to org.apache.commons.lang3.function.
+ *
+ * @param Input type 1.
+ * @param Input type 2.
+ * @param Return type.
+ * @param Thrown exception.
+ * @deprecated Use {@link org.apache.commons.lang3.function.FailableBiFunction}.
+ */
+ @Deprecated
@FunctionalInterface
- public interface FailableCallable {
+ public interface FailableBiFunction {
+
/**
- * Calls the callable.
- * @return The value returned from the callable
- * @throws T if the callable fails
+ * Applies this function.
+ *
+ * @param input1 The first input for the function
+ * @param input2 The second input for the function
+ * @return The result of the function
+ * @throws T Thrown when the function fails.
*/
- O call() throws T;
+ R apply(O1 input1, O2 input2) throws T;
}
+ /**
+ * A functional interface like {@link BiPredicate} that declares a {@link Throwable}.
+ *
+ *
TODO for 4.0: Move to org.apache.commons.lang3.function.
+ *
+ * @param Predicate type 1.
+ * @param Predicate type 2.
+ * @param Thrown exception.
+ * @deprecated Use {@link org.apache.commons.lang3.function.FailableBiPredicate}.
+ */
+ @Deprecated
@FunctionalInterface
- public interface FailableConsumer {
+ public interface FailableBiPredicate {
+
/**
- * Accepts the consumer.
- * @param pObject the parameter for the consumable to accept
- * @throws T if the consumer fails
+ * Tests the predicate.
+ *
+ * @param object1 The first object to test the predicate on
+ * @param object2 The second object to test the predicate on
+ * @return The predicate's evaluation
+ * @throws T if the predicate fails
*/
- void accept(O pObject) throws T;
+ boolean test(O1 object1, O2 object2) throws T;
}
+ /**
+ * A functional interface like {@link java.util.concurrent.Callable} that declares a {@link Throwable}.
+ *
+ *
TODO for 4.0: Move to org.apache.commons.lang3.function.
+ *
+ * @param Return type.
+ * @param Thrown exception.
+ * @deprecated Use {@link org.apache.commons.lang3.function.FailableCallable}.
+ */
+ @Deprecated
@FunctionalInterface
- public interface FailableBiConsumer {
+ public interface FailableCallable {
+
/**
- * Accepts the consumer.
- * @param pObject1 the first parameter for the consumable to accept
- * @param pObject2 the second parameter for the consumable to accept
- * @throws T if the consumer fails
+ * Calls the callable.
+ *
+ * @return The value returned from the callable
+ * @throws T if the callable fails
*/
- void accept(O1 pObject1, O2 pObject2) throws T;
+ R call() throws T;
}
+ /**
+ * A functional interface like {@link Consumer} that declares a {@link Throwable}.
+ *
+ *
TODO for 4.0: Move to org.apache.commons.lang3.function.
+ *
+ * @param Consumed type 1.
+ * @param Thrown exception.
+ * @deprecated Use {@link org.apache.commons.lang3.function.FailableConsumer}.
+ */
+ @Deprecated
@FunctionalInterface
- public interface FailableFunction {
+ public interface FailableConsumer {
+
/**
- * Apply the function.
- * @param pInput the input for the function
- * @return the result of the function
- * @throws T if the function fails
+ * Accepts the consumer.
+ *
+ * @param object The parameter for the consumable to accept
+ * @throws T Thrown when the consumer fails.
*/
- O apply(I pInput) throws T;
+ void accept(O object) throws T;
}
+ /**
+ * A functional interface like {@link Function} that declares a {@link Throwable}.
+ *
+ *
TODO for 4.0: Move to org.apache.commons.lang3.function.
+ *
+ * @param Input type 1.
+ * @param Return type.
+ * @param Thrown exception.
+ * @deprecated Use {@link org.apache.commons.lang3.function.FailableFunction}.
+ */
+ @Deprecated
@FunctionalInterface
- public interface FailableBiFunction {
+ public interface FailableFunction {
+
/**
- * Apply the function.
- * @param pInput1 the first input for the function
- * @param pInput2 the second input for the function
- * @return the result of the function
- * @throws T if the function fails
+ * Applies this function.
+ *
+ * @param input The input for the function
+ * @return The result of the function
+ * @throws T Thrown when the function fails.
*/
- O apply(I1 pInput1, I2 pInput2) throws T;
+ R apply(I input) throws T;
}
+ /**
+ * A functional interface like {@link Predicate} that declares a {@link Throwable}.
+ *
+ *
TODO for 4.0: Move to org.apache.commons.lang3.function.
+ *
+ * @param Predicate type 1.
+ * @param Thrown exception.
+ * @deprecated Use {@link org.apache.commons.lang3.function.FailablePredicate}.
+ */
+ @Deprecated
@FunctionalInterface
- public interface FailablePredicate {
+ public interface FailablePredicate {
+
/**
- * Test the predicate.
- * @param pObject the object to test the predicate on
- * @return the predicate's evaluation
+ * Tests the predicate.
+ *
+ * @param object The object to test the predicate on
+ * @return The predicate's evaluation
* @throws T if the predicate fails
*/
- boolean test(O pObject) throws T;
+ boolean test(I object) throws T;
}
+ /**
+ * A functional interface like {@link Runnable} that declares a {@link Throwable}.
+ *
+ *
TODO for 4.0: Move to org.apache.commons.lang3.function.
+ *
+ * @param Thrown exception.
+ * @deprecated Use {@link org.apache.commons.lang3.function.FailableRunnable}.
+ */
+ @Deprecated
@FunctionalInterface
- public interface FailableBiPredicate {
+ public interface FailableRunnable {
+
/**
- * Test the predicate.
- * @param pObject1 the first object to test the predicate on
- * @param pObject2 the second object to test the predicate on
- * @return the predicate's evaluation
- * @throws T if the predicate fails
+ * Runs the function.
+ *
+ * @throws T Thrown when the function fails.
*/
- boolean test(O1 pObject1, O2 pObject2) throws T;
+ void run() throws T;
}
+ /**
+ * A functional interface like {@link Supplier} that declares a {@link Throwable}.
+ *
+ *
TODO for 4.0: Move to org.apache.commons.lang3.function.
+ *
+ * @param Return type.
+ * @param Thrown exception.
+ * @deprecated Use {@link org.apache.commons.lang3.function.FailableSupplier}.
+ */
+ @Deprecated
@FunctionalInterface
- public interface FailableSupplier {
+ public interface FailableSupplier {
+
/**
* Supplies an object
- * @return the suppliers result
+ *
+ * @return A result
* @throws T if the supplier fails
*/
- O get() throws T;
+ R get() throws T;
}
/**
- * Converts the given {@link FailableRunnable} into a standard {@link Runnable}.
+ * Consumes a consumer and rethrows any exception as a {@link RuntimeException}.
*
- * @param pRunnable a {@code FailableRunnable}
- * @return a standard {@code Runnable}
+ * @param consumer The consumer to consume
+ * @param object1 The first object to consume by {@code consumer}
+ * @param object2 The second object to consume by {@code consumer}
+ * @param the type of the first argument the consumer accepts
+ * @param the type of the second argument the consumer accepts
+ * @param The type of checked exception the consumer may throw
*/
- public static Runnable asRunnable(FailableRunnable> pRunnable) {
- return () -> run(pRunnable);
+ public static void accept(final FailableBiConsumer consumer,
+ final O1 object1, final O2 object2) {
+ run(() -> consumer.accept(object1, object2));
}
/**
- * Converts the given {@link FailableConsumer} into a standard {@link Consumer}.
+ * Consumes a consumer and rethrows any exception as a {@link RuntimeException}.
*
- * @param the type used by the consumers
- * @param pConsumer a {@code FailableConsumer}
- * @return a standard {@code Consumer}
+ * @param consumer The consumer to consume
+ * @param object The object to consume by {@code consumer}
+ * @param The type the consumer accepts
+ * @param The type of checked exception the consumer may throw
*/
- public static Consumer asConsumer(FailableConsumer pConsumer) {
- return (pInput) -> accept(pConsumer, pInput);
+ public static void accept(final FailableConsumer consumer, final O object) {
+ run(() -> consumer.accept(object));
}
/**
- * Converts the given {@link FailableCallable} into a standard {@link Callable}.
+ * Applies a function and rethrows any exception as a {@link RuntimeException}.
*
- * @param the type used by the callables
- * @param pCallable a {@code FailableCallable}
- * @return a standard {@code Callable}
+ * @param function The function to apply
+ * @param input1 The first input to apply {@code function} on
+ * @param input2 The second input to apply {@code function} on
+ * @param the type of the first argument the function accepts
+ * @param the type of the second argument the function accepts
+ * @param The return type of the function
+ * @param The type of checked exception the function may throw
+ * @return The value returned from the function
*/
- public static Callable asCallable(FailableCallable pCallable) {
- return () -> call(pCallable);
+ public static O apply(final FailableBiFunction function,
+ final O1 input1, final O2 input2) {
+ return get(() -> function.apply(input1, input2));
}
/**
- * Converts the given {@link FailableBiConsumer} into a standard {@link BiConsumer}.
+ * Applies a function and rethrows any exception as a {@link RuntimeException}.
*
- * @param the type of the first argument of the consumers
- * @param the type of the second argument of the consumers
- * @param pConsumer a failable {@code BiConsumer}
- * @return a standard {@code BiConsumer}
+ * @param function The function to apply
+ * @param input The input to apply {@code function} on
+ * @param The type of the argument the function accepts
+ * @param The return type of the function
+ * @param The type of checked exception the function may throw
+ * @return The value returned from the function
*/
- public static BiConsumer asBiConsumer(FailableBiConsumer pConsumer) {
- return (pInput1, pInput2) -> accept(pConsumer, pInput1, pInput2);
+ public static O apply(final FailableFunction function, final I input) {
+ return get(() -> function.apply(input));
}
/**
- * Converts the given {@link FailableFunction} into a standard {@link Function}.
+ * Converts the given {@link FailableBiConsumer} into a standard {@link BiConsumer}.
*
- * @param the type of the input of the functions
- * @param the type of the output of the functions
- * @param pFunction a {code FailableFunction}
- * @return a standard {@code Function}
+ * @param the type of the first argument of the consumers
+ * @param the type of the second argument of the consumers
+ * @param consumer A failable {@link BiConsumer}
+ * @return A standard {@link BiConsumer}
+ * @since 3.10
*/
- public static Function asFunction(FailableFunction pFunction) {
- return (pInput) -> apply(pFunction, pInput);
+ public static BiConsumer asBiConsumer(final FailableBiConsumer consumer) {
+ return (input1, input2) -> accept(consumer, input1, input2);
}
/**
* Converts the given {@link FailableBiFunction} into a standard {@link BiFunction}.
*
- * @param the type of the first argument of the input of the functions
- * @param the type of the second argument of the input of the functions
- * @param the type of the output of the functions
- * @param pFunction a {@code FailableBiFunction}
- * @return a standard {@code BiFunction}
+ * @param