├── .github ├── PULL_REQUEST_TEMPLATE.md └── hibernate-github-bot.yml ├── .gitignore ├── .release └── .gitignore ├── LICENSE ├── build.gradle ├── ci └── release │ └── Jenkinsfile ├── dco.txt ├── gradle.properties ├── gradle ├── base-information.gradle ├── publishing.gradle ├── version.properties └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── readme.md ├── settings.gradle ├── spotless.license.java └── src ├── main ├── java │ ├── module-info.java │ └── org │ │ └── hibernate │ │ └── annotations │ │ └── common │ │ ├── annotationfactory │ │ ├── AnnotationDescriptor.java │ │ ├── AnnotationFactory.java │ │ └── AnnotationProxy.java │ │ └── reflection │ │ ├── AnnotationReader.java │ │ ├── Filter.java │ │ ├── MetadataProvider.java │ │ ├── MetadataProviderInjector.java │ │ ├── ReflectionManager.java │ │ ├── ReflectionUtil.java │ │ ├── XAnnotatedElement.java │ │ ├── XClass.java │ │ ├── XMember.java │ │ ├── XMethod.java │ │ ├── XPackage.java │ │ ├── XProperty.java │ │ └── java │ │ ├── JavaAnnotationReader.java │ │ ├── JavaMetadataProvider.java │ │ ├── JavaReflectionManager.java │ │ ├── JavaXAnnotatedElement.java │ │ ├── JavaXArrayType.java │ │ ├── JavaXClass.java │ │ ├── JavaXCollectionType.java │ │ ├── JavaXMember.java │ │ ├── JavaXMethod.java │ │ ├── JavaXPackage.java │ │ ├── JavaXProperty.java │ │ ├── JavaXSimpleType.java │ │ ├── JavaXType.java │ │ ├── TypeEnvironmentMap.java │ │ ├── XTypeConstruction.java │ │ └── generics │ │ ├── ApproximatingTypeEnvironment.java │ │ ├── CompoundTypeEnvironment.java │ │ ├── GenericArrayTypeImpl.java │ │ ├── IdentityTypeEnvironment.java │ │ ├── ParameterizedTypeImpl.java │ │ ├── SimpleTypeEnvironment.java │ │ ├── TypeEnvironment.java │ │ ├── TypeEnvironmentFactory.java │ │ ├── TypeFactory.java │ │ ├── TypeSwitch.java │ │ └── TypeUtils.java └── javadoc │ ├── jdstyle.css │ └── package.html └── test ├── java └── org │ └── hibernate │ └── annotations │ └── common │ └── test │ ├── annotationfactory │ ├── AnnotationFactoryTest.java │ ├── AnnotationProxyTest.java │ └── TestAnnotation.java │ └── reflection │ └── java │ ├── Foo.java │ ├── FooFather.java │ ├── JavaReflectionManagerTest.java │ ├── JavaXClassTest.java │ ├── JavaXPropertyTest.java │ ├── Sex.java │ ├── TestAnnotation.java │ ├── XAnnotatedElementTestCase.java │ └── generics │ ├── ApproximatingTypeEnvironmentTest.java │ ├── BigBlob.java │ ├── CircularGeneric.java │ ├── Dad.java │ ├── Grandpa.java │ ├── Language.java │ ├── MultipleBoundWithClass.java │ ├── MultipleBoundWithMultipleInterfaces.java │ ├── Neighbour.java │ ├── Son.java │ ├── SonOfBlob.java │ ├── TestAnnotation.java │ ├── TypeEnvironmentFactoryTest.java │ ├── TypeUtilsTest.java │ ├── UnboundGeneric.java │ └── deep │ ├── ANN612IssueTest.java │ ├── DeepGenericsContainment.java │ ├── DeepGenericsInheritance.java │ ├── Dummy.java │ ├── DummySubclass.java │ ├── GenericSuperclass1.java │ ├── GenericSuperclass2.java │ ├── Subclass1.java │ └── Subclass2.java ├── java17 └── org │ └── hibernate │ └── annotations │ └── common │ └── test │ └── reflection │ └── java │ └── records │ └── JavaXPropertyTest.java └── resources └── log4j.properties /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 11 | 12 | [Please describe here what your change is about] 13 | 14 | 17 | ---------------------- 18 | By submitting this pull request, I confirm that my contribution is made under the terms of the [Apache 2.0 license](https://www.apache.org/licenses/LICENSE-2.0.txt) 19 | and can be relicensed under the terms of the [LGPL v2.1 license](https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt) in the future at the maintainers' discretion. 20 | For more information on licensing, please check [here](https://github.com/hibernate/hibernate-commons-annotations/blob/main/readme.md). 21 | 22 | ---------------------- 23 | -------------------------------------------------------------------------------- /.github/hibernate-github-bot.yml: -------------------------------------------------------------------------------- 1 | --- 2 | jira: 3 | projectKey: "HCANN" 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Typically *NIX text editors, by default, append '~' to files on saving to make backups 2 | *~ 3 | 4 | # Gradle work directory 5 | .gradle 6 | 7 | # Build output directies 8 | /target 9 | */target 10 | /build 11 | */build 12 | 13 | # IntelliJ specific files/directories 14 | out 15 | .idea 16 | *.ipr 17 | *.iws 18 | *.iml 19 | atlassian-ide-plugin.xml 20 | 21 | # Eclipse specific files/directories 22 | .classpath 23 | .project 24 | .settings 25 | .metadata 26 | bin 27 | 28 | # NetBeans specific files/directories 29 | .nbattrs 30 | 31 | # Miscellaneous 32 | *.log 33 | .clover 34 | -------------------------------------------------------------------------------- /.release/.gitignore: -------------------------------------------------------------------------------- 1 | # This is the folder into which we check out our release scripts 2 | * -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | mavenCentral() 4 | gradlePluginPortal() 5 | } 6 | dependencies { 7 | classpath 'org.hibernate.build.gradle:gradle-maven-publish-auth:2.0.1' 8 | classpath 'org.hibernate.build.gradle:gradle-animalSniffer-plugin:1.0.1.Final' 9 | classpath "com.diffplug.spotless:spotless-plugin-gradle:6.25.0" 10 | classpath 'nu.studer:gradle-credentials-plugin:2.2' 11 | } 12 | } 13 | 14 | plugins { 15 | id 'java-library' 16 | id 'maven-publish' 17 | id 'nu.studer.credentials' version '2.1' 18 | id 'idea' 19 | id 'eclipse' 20 | } 21 | 22 | repositories { 23 | mavenCentral() 24 | } 25 | 26 | apply from: rootProject.file( 'gradle/base-information.gradle' ) 27 | apply from: rootProject.file( 'gradle/publishing.gradle' ) 28 | 29 | apply plugin: 'com.diffplug.spotless' 30 | 31 | dependencies { 32 | testImplementation 'junit:junit:3.8.1' 33 | } 34 | 35 | wrapper { 36 | distributionType = Wrapper.DistributionType.ALL 37 | } 38 | 39 | spotless { 40 | //Don't fail during the check: rather than enforcing guidelines, we use this plugin to fix mistakes automatically. 41 | enforceCheck false 42 | java { 43 | licenseHeaderFile 'spotless.license.java' 44 | removeUnusedImports() 45 | importOrder() 46 | trimTrailingWhitespace() 47 | endWithNewline() 48 | } 49 | } 50 | tasks.compileJava.dependsOn(spotlessApply) 51 | 52 | compileJava.options.encoding = 'UTF-8' 53 | compileTestJava.options.encoding = 'UTF-8' 54 | 55 | // Main binaries use a Java 11 baseline 56 | compileJava { 57 | sourceCompatibility = 11 58 | targetCompatibility = 11 59 | } 60 | // ... and we want to test against that 61 | compileTestJava { 62 | sourceCompatibility = 11 63 | targetCompatibility = 11 64 | } 65 | 66 | // Some tests require Java 17 67 | if ( !JavaVersion.current().isCompatibleWith( JavaVersion.VERSION_17 ) ) { 68 | throw new IllegalStateException("Building this project requires JDK 17 (produced binaries will still target Java 11).") 69 | } 70 | java { 71 | toolchain { 72 | languageVersion.set(JavaLanguageVersion.of(17)) 73 | } 74 | } 75 | 76 | // We add a new source set, which contains tests that can run on JDK17+ 77 | sourceSets { 78 | testJava17 { 79 | java { 80 | srcDirs = ['src/test/java17'] 81 | } 82 | } 83 | } 84 | 85 | // For the new source set, we need to configure the source and target version to 17 86 | compileTestJava17Java { 87 | sourceCompatibility = 17 88 | targetCompatibility = 17 89 | } 90 | 91 | // The source set gets a custom configuration which extends the normal test implementation config 92 | configurations { 93 | testJava17Implementation.extendsFrom(testImplementation, testRuntimeOnly) 94 | testJava17CompileOnly.extendsFrom(testCompileOnly) 95 | } 96 | 97 | // Add the output from src/main/java as dependency 98 | dependencies { 99 | testJava17Implementation files(sourceSets.main.output.classesDirs) { 100 | builtBy compileJava 101 | } 102 | } 103 | 104 | // We execute the Java 17 tests in a custom test task 105 | task testJava17(type: Test) { 106 | testClassesDirs = sourceSets.testJava17.output.classesDirs 107 | classpath = sourceSets.testJava17.runtimeClasspath 108 | } 109 | 110 | testClasses.dependsOn compileTestJava17Java 111 | // And run this as part of the check task by default 112 | check.dependsOn testJava17 -------------------------------------------------------------------------------- /ci/release/Jenkinsfile: -------------------------------------------------------------------------------- 1 | #! /usr/bin/groovy 2 | /* 3 | * SPDX-License-Identifier: Apache-2.0 4 | * Copyright: Red Hat Inc. and Hibernate Authors 5 | */ 6 | 7 | /* 8 | * See https://github.com/hibernate/hibernate-jenkins-pipeline-helpers 9 | */ 10 | @Library('hibernate-jenkins-pipeline-helpers@1.17') _ 11 | 12 | import org.hibernate.jenkins.pipeline.helpers.version.Version 13 | 14 | // -------------------------------------------- 15 | // Global build configuration 16 | env.PROJECT = "hcann" 17 | env.JIRA_KEY = "HCANN" 18 | 19 | print "INFO: env.PROJECT = ${env.PROJECT}" 20 | print "INFO: env.JIRA_KEY = ${env.JIRA_KEY}" 21 | 22 | // -------------------------------------------- 23 | // Build conditions 24 | 25 | // Avoid running the pipeline on branch indexing 26 | if (currentBuild.getBuildCauses().toString().contains('BranchIndexingCause')) { 27 | print "INFO: Build skipped due to trigger being Branch Indexing" 28 | currentBuild.result = 'NOT_BUILT' 29 | return 30 | } 31 | 32 | def manualRelease = currentBuild.getBuildCauses().toString().contains( 'UserIdCause' ) 33 | 34 | // Avoid running the pipeline on push 35 | if ( !manualRelease ) { 36 | print "INFO: Build skipped because automated releases are disabled." 37 | currentBuild.result = 'NOT_BUILT' 38 | return 39 | } 40 | 41 | // -------------------------------------------- 42 | // Reusable methods 43 | 44 | def checkoutReleaseScripts() { 45 | dir('.release/scripts') { 46 | checkout scmGit(branches: [[name: '*/main']], extensions: [], 47 | userRemoteConfigs: [[credentialsId: 'ed25519.Hibernate-CI.github.com', 48 | url: 'https://github.com/hibernate/hibernate-release-scripts.git']]) 49 | } 50 | } 51 | 52 | // -------------------------------------------- 53 | // Pipeline 54 | 55 | pipeline { 56 | agent { 57 | label 'Release' 58 | } 59 | tools { 60 | jdk 'OpenJDK 17 Latest' 61 | } 62 | options { 63 | buildDiscarder logRotator(daysToKeepStr: '30', numToKeepStr: '10') 64 | disableConcurrentBuilds(abortPrevious: false) 65 | preserveStashes() 66 | } 67 | parameters { 68 | string( 69 | name: 'RELEASE_VERSION', 70 | defaultValue: '', 71 | description: 'The version to be released, e.g. 7.0.1.Final. Mandatory, to prevent mistakes.', 72 | trim: true 73 | ) 74 | string( 75 | name: 'DEVELOPMENT_VERSION', 76 | defaultValue: '', 77 | description: 'The next version to be used after the release, e.g. 7.0.2-SNAPSHOT. If not set, determined automatically from the release version.', 78 | trim: true 79 | ) 80 | booleanParam( 81 | name: 'RELEASE_DRY_RUN', 82 | defaultValue: false, 83 | description: 'If true, just simulate the release, without pushing any commits or tags, and without uploading any artifacts or documentation.' 84 | ) 85 | } 86 | stages { 87 | stage('Release check') { 88 | steps { 89 | script { 90 | checkoutReleaseScripts() 91 | 92 | def currentVersion = Version.parseDevelopmentVersion( sh( 93 | script: ".release/scripts/determine-current-version.sh ${env.PROJECT}", 94 | returnStdout: true 95 | ).trim() ) 96 | echo "Workspace version: ${currentVersion}" 97 | 98 | def releaseVersion 99 | def developmentVersion 100 | 101 | echo "Release was requested manually" 102 | 103 | if ( !params.RELEASE_VERSION ) { 104 | throw new IllegalArgumentException( 'Missing value for parameter RELEASE_VERSION. This parameter must be set explicitly to prevent mistakes.' ) 105 | } 106 | releaseVersion = Version.parseReleaseVersion( params.RELEASE_VERSION ) 107 | 108 | if ( !releaseVersion.toString().startsWith( currentVersion.family + '.' ) ) { 109 | throw new IllegalArgumentException( "RELEASE_VERSION = $releaseVersion, which is different from the family of CURRENT_VERSION = $currentVersion. Did you make a mistake?" ) 110 | } 111 | echo "Release version: ${releaseVersion}" 112 | 113 | if ( !params.DEVELOPMENT_VERSION ) { 114 | developmentVersion = Version.parseDevelopmentVersion( sh( 115 | script: ".release/scripts/determine-development-version.sh ${releaseVersion}", 116 | returnStdout: true 117 | ).trim() ) 118 | } 119 | else { 120 | developmentVersion = Version.parseDevelopmentVersion( params.DEVELOPMENT_VERSION ) 121 | } 122 | echo "Development version: ${developmentVersion}" 123 | 124 | env.RELEASE_VERSION = releaseVersion.toString() 125 | env.DEVELOPMENT_VERSION = developmentVersion.toString() 126 | env.SCRIPT_OPTIONS = params.RELEASE_DRY_RUN ? "-d" : "" 127 | } 128 | } 129 | } 130 | stage('Prepare release') { 131 | steps { 132 | script { 133 | checkoutReleaseScripts() 134 | 135 | // set release version 136 | // update changelog from JIRA 137 | // tag the version 138 | sh ".release/scripts/prepare-release.sh ${env.PROJECT} ${env.RELEASE_VERSION}" 139 | } 140 | } 141 | } 142 | stage('Publish release') { 143 | steps { 144 | script { 145 | checkoutReleaseScripts() 146 | 147 | configFileProvider([ 148 | configFile(fileId: 'release.config.ssh', targetLocation: "${env.HOME}/.ssh/config"), 149 | configFile(fileId: 'release.config.ssh.knownhosts', targetLocation: "${env.HOME}/.ssh/known_hosts") 150 | ]) { 151 | withCredentials([ 152 | usernamePassword(credentialsId: 'ossrh.sonatype.org', passwordVariable: 'OSSRH_PASSWORD', usernameVariable: 'OSSRH_USER'), 153 | ]) { 154 | sshagent(['ed25519.Hibernate-CI.github.com']) { 155 | // perform documentation upload and Sonatype release 156 | // change the version to the development version 157 | // push to github 158 | sh ".release/scripts/publish.sh ${env.SCRIPT_OPTIONS} ${env.PROJECT} ${env.RELEASE_VERSION} ${env.DEVELOPMENT_VERSION} ${env.GIT_BRANCH}" 159 | } 160 | } 161 | } 162 | } 163 | } 164 | } 165 | } 166 | post { 167 | always { 168 | notifyBuildResult notifySuccessAfterSuccess: true, maintainers: 'yoann@hibernate.org' 169 | } 170 | } 171 | } -------------------------------------------------------------------------------- /dco.txt: -------------------------------------------------------------------------------- 1 | Developer Certificate of Origin 2 | Version 1.1 3 | 4 | Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 5 | 1 Letterman Drive 6 | Suite D4700 7 | San Francisco, CA, 94129 8 | 9 | Everyone is permitted to copy and distribute verbatim copies of this 10 | license document, but changing it is not allowed. 11 | 12 | 13 | Developer's Certificate of Origin 1.1 14 | 15 | By making a contribution to this project, I certify that: 16 | 17 | (a) The contribution was created in whole or in part by me and I 18 | have the right to submit it under the open source license 19 | indicated in the file; or 20 | 21 | (b) The contribution is based upon previous work that, to the best 22 | of my knowledge, is covered under an appropriate open source 23 | license and I have the right under that license to submit that 24 | work with modifications, whether created in whole or in part 25 | by me, under the same open source license (unless I am 26 | permitted to submit under a different license), as indicated 27 | in the file; or 28 | 29 | (c) The contribution was provided directly to me by some other 30 | person who certified (a), (b) or (c) and I have not modified 31 | it. 32 | 33 | (d) I understand and agree that this project and the contribution 34 | are public and that a record of the contribution (including all 35 | personal information I submit with it, including my sign-off) is 36 | maintained indefinitely and may be redistributed consistent with 37 | this project or the open source license(s) involved. -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hibernate/hibernate-commons-annotations/0595f983b2b2e3b6de1251c16a5fee9507dd07be/gradle.properties -------------------------------------------------------------------------------- /gradle/base-information.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'base' 2 | 3 | File versionFile = file( "${rootProject.projectDir}/gradle/version.properties" ) 4 | 5 | ext { 6 | hcannVersionFile = versionFile 7 | hcannVersion = HibernateVersion.fromFile( versionFile, project ) 8 | // Override during releases 9 | if ( project.hasProperty( 'releaseVersion' ) ) { 10 | hcannVersion = new HibernateVersion( project.releaseVersion, project ) 11 | } 12 | } 13 | 14 | group = 'org.hibernate.common' 15 | version = project.hcannVersion.fullName 16 | 17 | buildDir = "target" 18 | 19 | java { 20 | toolchain { 21 | languageVersion.set(JavaLanguageVersion.of(11)) 22 | } 23 | } 24 | 25 | class HibernateVersion { 26 | final String fullName 27 | final String majorVersion 28 | final String family 29 | 30 | final String osgiVersion 31 | 32 | final boolean isSnapshot 33 | 34 | HibernateVersion(String fullName, Project project) { 35 | this.fullName = fullName 36 | 37 | final String[] hibernateVersionComponents = fullName.split( '\\.' ) 38 | this.majorVersion = hibernateVersionComponents[0] 39 | this.family = hibernateVersionComponents[0] + '.' + hibernateVersionComponents[1] 40 | 41 | this.isSnapshot = fullName.endsWith( '-SNAPSHOT' ) 42 | 43 | this.osgiVersion = isSnapshot ? family + '.' + hibernateVersionComponents[2] + '.SNAPSHOT' : fullName 44 | } 45 | 46 | static HibernateVersion fromFile(File file, Project project){ 47 | def fullName = readVersionProperties(file) 48 | return new HibernateVersion(fullName, project) 49 | } 50 | 51 | private static String readVersionProperties(File file) { 52 | if ( !file.exists() ) { 53 | throw new GradleException( "Version file $file.canonicalPath does not exists" ) 54 | } 55 | Properties versionProperties = new Properties() 56 | file.withInputStream { 57 | stream -> versionProperties.load( stream ) 58 | } 59 | return versionProperties.hibernateVersion 60 | } 61 | 62 | @Override 63 | String toString() { 64 | return this.fullName 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /gradle/publishing.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'maven-publish' 2 | apply plugin: 'nu.studer.credentials' 3 | 4 | ext { 5 | if ( System.getenv( 'OSSRH_USER' ) ) { 6 | credentials.ossrhUsername = System.getenv( 'OSSRH_USER' ) 7 | } 8 | if ( System.getenv( 'OSSRH_PASSWORD' ) ) { 9 | credentials.ossrhPassword = System.getenv( 'OSSRH_PASSWORD' ) 10 | } 11 | 12 | gradle.taskGraph.addTaskExecutionGraphListener( 13 | new TaskExecutionGraphListener() { 14 | @Override 15 | void graphPopulated(TaskExecutionGraph graph) { 16 | if ( graph.hasTask( 'publishMavenJavaPublicationToSnapshotRepository' ) ) { 17 | if ( ! project.hcannVersion.isSnapshot ) { 18 | throw new GradleException("Cannot publish non-snapshot version to snapshot repository"); 19 | } 20 | if ( project.credentials.ossrhUsername == null ) { 21 | throw new GradleException("Snapshot publishing credentials not specified"); 22 | } 23 | } 24 | 25 | if (graph.hasTask('publishMavenJavaPublicationToOssrhRepository')) { 26 | if ( project.hcannVersion.isSnapshot ) { 27 | throw new GradleException("Cannot publish snapshot version to non-snapshot repository"); 28 | } 29 | if (project.credentials.ossrhUsername == null) { 30 | throw new GradleException("Publishing credentials not specified"); 31 | } 32 | } 33 | } 34 | } 35 | ) 36 | } 37 | 38 | java { 39 | withJavadocJar() 40 | withSourcesJar() 41 | } 42 | 43 | jar { 44 | manifest { 45 | attributes( 46 | 'Main-Class': 'org.hibernate.Version', 47 | 48 | 'Implementation-Url': 'http://hibernate.org', 49 | 'Implementation-Version': archiveVersion, 50 | 'Implementation-Vendor': 'Hibernate.org', 51 | 'Implementation-Vendor-Id': 'org.hibernate', 52 | 'Bundle-Vendor': 'Hibernate.org' 53 | ) 54 | // 55 | // // See https://discuss.gradle.org/t/balancing-deprecation-of-sourcesetoutput-classesdir-and-other-parts-of-gradle-that-only-accept-a-dir-file/25283 56 | // classesDir = sourceSets.main.java.outputDir 57 | // classpath = configurations.runtime 58 | } 59 | } 60 | 61 | OsgiManifestPackagingInfo.buildInfo( project ).applyTo( jar.manifest ) 62 | 63 | task sourceJar(type: Jar) { 64 | from sourceSets.main.allJava 65 | } 66 | 67 | javadoc { 68 | configure( options ) { 69 | windowTitle = "$project.name JavaDocs" 70 | docTitle = "$project.name JavaDocs ($project.version)" 71 | use = true 72 | encoding = 'UTF-8' 73 | links += ['https://docs.oracle.com/en/java/javase/11/docs/api/'] 74 | tags = ["apiNote", 'implSpec', 'implNote', 'todo'] 75 | 76 | addStringOption('Xdoclint:none', '-quiet') 77 | } 78 | } 79 | 80 | publishing { 81 | publications { 82 | mavenJava(MavenPublication) { 83 | from components.java 84 | 85 | pom { 86 | name = 'Hibernate Commons Annotations' 87 | description = 'Common reflection code used in support of annotation processing' 88 | url = 'http://hibernate.org' 89 | 90 | organization { 91 | name = 'Hibernate.org' 92 | url = 'http://hibernate.org' 93 | } 94 | 95 | licenses { 96 | license { 97 | name = 'Apache License Version 2.0' 98 | url = 'https://opensource.org/licenses/Apache-2.0' 99 | comments = 'See http://hibernate.org/community/license/ for more details.' 100 | distribution = 'repo' 101 | } 102 | } 103 | 104 | scm { 105 | url = 'http://github.com/hibernate/hibernate-commons-annotations' 106 | connection = 'scm:git:http://github.com/hibernate/hibernate-commons-annotations.git' 107 | developerConnection = 'scm:git:git@github.com:hibernate/hibernate-commons-annotations.git' 108 | } 109 | 110 | issueManagement { 111 | system = 'jira' 112 | url = 'https://hibernate.atlassian.net/browse/HCANN' 113 | } 114 | 115 | developers { 116 | developer { 117 | id = 'hibernate-team' 118 | name = 'The Hibernate Development Team' 119 | organization = 'Hibernate.org' 120 | organizationUrl = 'http://hibernate.org' 121 | } 122 | } 123 | } 124 | } 125 | } 126 | 127 | repositories { 128 | maven { 129 | if ( project.hcannVersion.isSnapshot ) { 130 | name 'snapshots' 131 | url 'https://oss.sonatype.org/content/repositories/snapshots/' 132 | } 133 | else { 134 | name 'ossrh' 135 | url 'https://oss.sonatype.org/service/local/staging/deploy/maven2/' 136 | } 137 | 138 | credentials { 139 | username project.credentials.ossrhUsername 140 | password project.credentials.ossrhPassword 141 | } 142 | } 143 | } 144 | } 145 | 146 | // OSGi manifest helpers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 147 | 148 | class OsgiManifestPackagingInfo { 149 | private String[] exportPackageInstructions; 150 | private String[] privatePackageInstructions; 151 | 152 | String[] getExportPackageInstructions() { 153 | return exportPackageInstructions 154 | } 155 | 156 | String[] getPrivatePackageInstructions() { 157 | return privatePackageInstructions 158 | } 159 | 160 | public static OsgiManifestPackagingInfo buildInfo(Project project) { 161 | final String exportPackageVersion = project.version.replaceAll( "-SNAPSHOT", "" ) 162 | .replaceAll( ".Final-redhat-", "DO_NOT_REPLACE" ) 163 | .replaceAll( ".Final", "" ) 164 | .replaceAll( "DO_NOT_REPLACE", ".Final-redhat-" ); 165 | 166 | final Set exportPackageInstructionSet = new HashSet() 167 | final Set privatePackageInstructionSet = new HashSet() 168 | 169 | final SourceDirectorySet sourceDirectorySet = project.sourceSets.main.java; 170 | sourceDirectorySet.each { javaSrcFile -> 171 | final String packageName = determinePackageName( sourceDirectorySet, javaSrcFile ); 172 | if ( packageName.endsWith( ".internal" ) 173 | || packageName.contains( ".internal." ) ) { 174 | privatePackageInstructionSet.add( packageName ); 175 | } 176 | else { 177 | exportPackageInstructionSet.add( packageName + ";version=\"" + exportPackageVersion + "\"" ); 178 | } 179 | } 180 | 181 | return new OsgiManifestPackagingInfo( 182 | exportPackageInstructionSet.toArray( new String[ exportPackageInstructionSet.size() ] ), 183 | privatePackageInstructionSet.toArray( new String[ privatePackageInstructionSet.size() ] ) 184 | ); 185 | } 186 | 187 | private static String determinePackageName(SourceDirectorySet sourceDirectorySet, File javaFile) { 188 | if (javaFile.name.equals("module-info.java")) { 189 | return ""; 190 | } 191 | final javaFileAbsolutePath = javaFile.absolutePath; 192 | for ( File sourceDirectory : sourceDirectorySet.srcDirs ) { 193 | final String sourceDirectoryAbsolutePath = sourceDirectory.absolutePath; 194 | if ( javaFileAbsolutePath.startsWith( sourceDirectoryAbsolutePath ) ) { 195 | final String javaFileRelativePath = javaFileAbsolutePath.substring( 196 | sourceDirectoryAbsolutePath.length() + 1, 197 | javaFileAbsolutePath.lastIndexOf( File.separator ) 198 | ); 199 | return javaFileRelativePath.replace( File.separator, "." ); 200 | } 201 | } 202 | throw new RuntimeException( "ugh" ); 203 | } 204 | 205 | private OsgiManifestPackagingInfo(String[] exportPackageInstructions, String[] privatePackageInstructions) { 206 | this.exportPackageInstructions = exportPackageInstructions 207 | this.privatePackageInstructions = privatePackageInstructions 208 | } 209 | 210 | def applyTo(def manifest) { 211 | if ( exportPackageInstructions.length > 0 ) { 212 | manifest.attributes( 'Export-Package': exportPackageInstructions ) 213 | } 214 | if ( privatePackageInstructions.length > 0 ) { 215 | manifest.attribute( 'Private-Package', privatePackageInstructions ) 216 | } 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /gradle/version.properties: -------------------------------------------------------------------------------- 1 | hibernateVersion=7.0.4-SNAPSHOT 2 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hibernate/hibernate-commons-annotations/0595f983b2b2e3b6de1251c16a5fee9507dd07be/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-all.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | # This is normally unused 84 | # shellcheck disable=SC2034 85 | APP_BASE_NAME=${0##*/} 86 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 87 | 88 | # Use the maximum available, or set MAX_FD != -1 to use that value. 89 | MAX_FD=maximum 90 | 91 | warn () { 92 | echo "$*" 93 | } >&2 94 | 95 | die () { 96 | echo 97 | echo "$*" 98 | echo 99 | exit 1 100 | } >&2 101 | 102 | # OS specific support (must be 'true' or 'false'). 103 | cygwin=false 104 | msys=false 105 | darwin=false 106 | nonstop=false 107 | case "$( uname )" in #( 108 | CYGWIN* ) cygwin=true ;; #( 109 | Darwin* ) darwin=true ;; #( 110 | MSYS* | MINGW* ) msys=true ;; #( 111 | NONSTOP* ) nonstop=true ;; 112 | esac 113 | 114 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 115 | 116 | 117 | # Determine the Java command to use to start the JVM. 118 | if [ -n "$JAVA_HOME" ] ; then 119 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 120 | # IBM's JDK on AIX uses strange locations for the executables 121 | JAVACMD=$JAVA_HOME/jre/sh/java 122 | else 123 | JAVACMD=$JAVA_HOME/bin/java 124 | fi 125 | if [ ! -x "$JAVACMD" ] ; then 126 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 127 | 128 | Please set the JAVA_HOME variable in your environment to match the 129 | location of your Java installation." 130 | fi 131 | else 132 | JAVACMD=java 133 | if ! command -v java >/dev/null 2>&1 134 | then 135 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 136 | 137 | Please set the JAVA_HOME variable in your environment to match the 138 | location of your Java installation." 139 | fi 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 147 | # shellcheck disable=SC3045 148 | MAX_FD=$( ulimit -H -n ) || 149 | warn "Could not query maximum file descriptor limit" 150 | esac 151 | case $MAX_FD in #( 152 | '' | soft) :;; #( 153 | *) 154 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 155 | # shellcheck disable=SC3045 156 | ulimit -n "$MAX_FD" || 157 | warn "Could not set maximum file descriptor limit to $MAX_FD" 158 | esac 159 | fi 160 | 161 | # Collect all arguments for the java command, stacking in reverse order: 162 | # * args from the command line 163 | # * the main class name 164 | # * -classpath 165 | # * -D...appname settings 166 | # * --module-path (only if needed) 167 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 168 | 169 | # For Cygwin or MSYS, switch paths to Windows format before running java 170 | if "$cygwin" || "$msys" ; then 171 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 172 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 173 | 174 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 175 | 176 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 177 | for arg do 178 | if 179 | case $arg in #( 180 | -*) false ;; # don't mess with options #( 181 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 182 | [ -e "$t" ] ;; #( 183 | *) false ;; 184 | esac 185 | then 186 | arg=$( cygpath --path --ignore --mixed "$arg" ) 187 | fi 188 | # Roll the args list around exactly as many times as the number of 189 | # args, so each arg winds up back in the position where it started, but 190 | # possibly modified. 191 | # 192 | # NB: a `for` loop captures its iteration list before it begins, so 193 | # changing the positional parameters here affects neither the number of 194 | # iterations, nor the values presented in `arg`. 195 | shift # remove old arg 196 | set -- "$@" "$arg" # push replacement arg 197 | done 198 | fi 199 | 200 | 201 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 202 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 203 | 204 | # Collect all arguments for the java command; 205 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 206 | # shell script including quotes and variable substitutions, so put them in 207 | # double quotes to make sure that they get re-expanded; and 208 | # * put everything else in single quotes, so that it's not re-expanded. 209 | 210 | set -- \ 211 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 212 | -classpath "$CLASSPATH" \ 213 | org.gradle.wrapper.GradleWrapperMain \ 214 | "$@" 215 | 216 | # Stop when "xargs" is not available. 217 | if ! command -v xargs >/dev/null 2>&1 218 | then 219 | die "xargs is not available" 220 | fi 221 | 222 | # Use "xargs" to parse quoted args. 223 | # 224 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 225 | # 226 | # In Bash we could simply go: 227 | # 228 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 229 | # set -- "${ARGS[@]}" "$@" 230 | # 231 | # but POSIX shell has neither arrays nor command substitution, so instead we 232 | # post-process each arg (as a line of input to sed) to backslash-escape any 233 | # character that might be a shell metacharacter, then use eval to reverse 234 | # that process (while maintaining the separation between arguments), and wrap 235 | # the whole thing up as a single "set" statement. 236 | # 237 | # This will of course break if any of these variables contains a newline or 238 | # an unmatched quote. 239 | # 240 | 241 | eval "set -- $( 242 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 243 | xargs -n1 | 244 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 245 | tr '\n' ' ' 246 | )" '"$@"' 247 | 248 | exec "$JAVACMD" "$@" 249 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | Hibernate Commons Annotations 2 | ================================================== 3 | 4 | Description 5 | ----------- 6 | 7 | Hibernate Commons Annotations is a utility project used by several Hibernate projects; 8 | as a user of Hibernate libraries you probably are not going to use this directly. 9 | 10 | Its first scope is to support Java Generics type discovery. 11 | Its second scope is to support Java Annotations overriding through XML files 12 | (mainly but not conceptually limited to). 13 | 14 | Requirements 15 | ------------ 16 | Since version 6.0 this project requires Java 11. 17 | 18 | Release Instructions 19 | ------------ 20 | 21 | Ensure JIRA is up to date and reflecting the state of the branch being released. 22 | 23 | Then start the release job on CI at https://ci.hibernate.org/view/Release/job/hibernate-commons-annotations-release/ 24 | 25 | Navigate to https://oss.sonatype.org/ to close and release the staged repository. 26 | 27 | Contact 28 | ------------ 29 | 30 | Latest Documentation: 31 | 32 | This project has no documentation per se, because of its internal use focus. 33 | Please ask questions to the technical support forum. 34 | 35 | Bug Reports: 36 | 37 | Hibernate JIRA (preferred): https://hibernate.atlassian.net 38 | 39 | Or contact us via chat, mailing list, etc as described on: 40 | 41 | http://hibernate.org/community/ 42 | 43 | Free, volunteers based technical support: 44 | 45 | https://discourse.hibernate.org 46 | 47 | 48 | Notes 49 | ----------- 50 | 51 | If you want to contribute, go to http://www.hibernate.org/ 52 | 53 | This software and its documentation are distributed under the terms of the 54 | Apache License Version 2.0. 55 | N.B. older versions of this library used a different license: LGPL 2.1. 56 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | if ( !JavaVersion.current().isJava11Compatible() ) { 2 | throw new GradleException( "Gradle must be run with Java 11" ) 3 | } 4 | 5 | rootProject.name = 'hibernate-commons-annotations' 6 | -------------------------------------------------------------------------------- /spotless.license.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ -------------------------------------------------------------------------------- /src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | module org.hibernate.commons.annotations { 2 | exports org.hibernate.annotations.common.annotationfactory; 3 | exports org.hibernate.annotations.common.reflection; 4 | exports org.hibernate.annotations.common.reflection.java; 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/annotationfactory/AnnotationDescriptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.annotationfactory; 6 | 7 | import java.lang.annotation.Annotation; 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | 11 | /** 12 | * Encapsulates the data you need to create an annotation. In 13 | * particular, it stores the type of an Annotation instance 14 | * and the values of its elements. 15 | * The "elements" we're talking about are the annotation attributes, 16 | * not its targets (the term "element" is used ambiguously 17 | * in Java's annotations documentation). 18 | * 19 | * @author Paolo Perrotta 20 | * @author Davide Marchignoli 21 | */ 22 | public final class AnnotationDescriptor { 23 | 24 | private final Class type; 25 | private Map elements; 26 | 27 | public AnnotationDescriptor(Class annotationType) { 28 | type = annotationType; 29 | } 30 | 31 | public void setValue(String elementName, Object value) { 32 | if ( elements == null ) { 33 | elements = new HashMap<>( 4 ); //likely to be small 34 | } 35 | elements.put( elementName, value ); 36 | } 37 | 38 | public Object valueOf(String elementName) { 39 | return elements == null ? null : elements.get( elementName ); 40 | } 41 | 42 | public boolean containsElement(String elementName) { 43 | return elements == null ? false : elements.containsKey( elementName ); 44 | } 45 | 46 | public int numberOfElements() { 47 | return elements == null ? 0 : elements.size(); 48 | } 49 | 50 | public Class type() { 51 | return type; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/annotationfactory/AnnotationFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.annotationfactory; 6 | 7 | import java.lang.annotation.Annotation; 8 | import java.lang.reflect.Proxy; 9 | 10 | /** 11 | * Creates live annotations (actually AnnotationProxies) from AnnotationDescriptors. 12 | * 13 | * @author Paolo Perrotta 14 | * @author Davide Marchignoli 15 | * @see AnnotationProxy 16 | */ 17 | public final class AnnotationFactory { 18 | 19 | /** 20 | * Creates an Annotation proxy for the given annotation descriptor. 21 | *

22 | * NOTE: the proxy here is generated using the ClassLoader of the Annotation type's Class. E.g., 23 | * if asked to create an Annotation proxy for javax.persistence.Entity we would use the ClassLoader 24 | * of the javax.persistence.Entity Class for generating the proxy. 25 | * 26 | * @param descriptor The annotation descriptor 27 | * 28 | * @return The annotation proxy 29 | */ 30 | public static T create(AnnotationDescriptor descriptor) { 31 | return create( descriptor, descriptor.type().getClassLoader() ); 32 | } 33 | 34 | /** 35 | * Legacy form of {@link #create(AnnotationDescriptor) using the current Thread#getContextClassLoader 36 | * for proxy generation 37 | * 38 | * @param descriptor The annotation descriptor 39 | * 40 | * @return The annotation proxy 41 | */ 42 | public static T createUsingTccl(AnnotationDescriptor descriptor) { 43 | return create( descriptor, Thread.currentThread().getContextClassLoader() ); 44 | } 45 | 46 | /** 47 | * Overloaded form of Annotation proxy creation that accepts an explicit ClassLoader. 48 | * 49 | * @param descriptor The annotation descriptor 50 | * @param classLoader The ClassLoader to be used in defining the proxy 51 | * 52 | * @return The annotation proxy 53 | */ 54 | @SuppressWarnings("unchecked") 55 | public static T create(AnnotationDescriptor descriptor, ClassLoader classLoader) { 56 | return (T) Proxy.newProxyInstance( 57 | classLoader, 58 | new Class[] {descriptor.type()}, 59 | new AnnotationProxy( descriptor ) 60 | ); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/annotationfactory/AnnotationProxy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.annotationfactory; 6 | 7 | import java.lang.annotation.Annotation; 8 | import java.lang.reflect.InvocationHandler; 9 | import java.lang.reflect.Method; 10 | import java.util.Collections; 11 | import java.util.Comparator; 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | import java.util.SortedSet; 15 | import java.util.TreeSet; 16 | 17 | /** 18 | * A concrete implementation of Annotation that pretends it is a 19 | * "real" source code annotation. It's also an InvocationHandler. 20 | *

21 | * When you create an AnnotationProxy, you must initialize it 22 | * with an AnnotationDescriptor. 23 | * The adapter checks that the provided elements are the same elements defined 24 | * in the annotation interface. However, it does not check that their 25 | * values are the right type. If you omit an element, the adapter will use the 26 | * default value for that element from the annotation interface, if it exists. 27 | * If no default exists, it will throw an exception. 28 | *

29 | * Warning: this class does not implement hashCode() and 30 | * equals() - it just uses the ones it inherits from Object. 31 | * This means that an AnnotationProxy does not follow the 32 | * recommendations of the Annotation javadoc about these two 33 | * methods. That's why you should never mix AnnotationProxies 34 | * with "real" annotations. For example, don't put them into the same 35 | * Collection. 36 | * 37 | * @author Paolo Perrotta 38 | * @author Davide Marchignoli 39 | * @see java.lang.annotation.Annotation 40 | */ 41 | public final class AnnotationProxy implements Annotation, InvocationHandler { 42 | 43 | private final Class annotationType; 44 | //FIXME it's probably better to use String as a key rather than Method 45 | // to speed up and avoid any fancy permsize/GC issue 46 | // I'd better check the litterature on the subject 47 | private final Map values; 48 | 49 | public AnnotationProxy(AnnotationDescriptor descriptor) { 50 | this.annotationType = descriptor.type(); 51 | this.values = getAnnotationValues( annotationType, descriptor ); 52 | } 53 | 54 | private static Map getAnnotationValues( 55 | Class annotationType, 56 | AnnotationDescriptor descriptor) { 57 | Map result = new HashMap(); 58 | int processedValuesFromDescriptor = 0; 59 | for ( Method m : annotationType.getDeclaredMethods() ) { 60 | if ( descriptor.containsElement( m.getName() ) ) { 61 | result.put( m, descriptor.valueOf( m.getName() ) ); 62 | processedValuesFromDescriptor++; 63 | } 64 | else if ( m.getDefaultValue() != null ) { 65 | result.put( m, m.getDefaultValue() ); 66 | } 67 | else { 68 | throw new IllegalArgumentException( "No value provided for " + m.getName() ); 69 | } 70 | } 71 | if ( processedValuesFromDescriptor != descriptor.numberOfElements() ) { 72 | throw new RuntimeException( "Trying to instanciate " + annotationType + " with unknown elements" ); 73 | } 74 | return toSmallMap( result ); 75 | } 76 | 77 | static Map toSmallMap(Map map) { 78 | switch ( map.size() ) { 79 | case 0: 80 | return Collections.emptyMap(); 81 | case 1: 82 | Map.Entry entry = map.entrySet().iterator().next(); 83 | return Collections.singletonMap( entry.getKey(), entry.getValue() ); 84 | default: 85 | return map; 86 | } 87 | } 88 | 89 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 90 | if ( values.containsKey( method ) ) { 91 | return values.get( method ); 92 | } 93 | return method.invoke( this, args ); 94 | } 95 | 96 | public Class annotationType() { 97 | return annotationType; 98 | } 99 | 100 | public String toString() { 101 | StringBuilder result = new StringBuilder(); 102 | result.append( '@' ).append( annotationType().getName() ).append( '(' ); 103 | for ( Method m : getRegisteredMethodsInAlphabeticalOrder() ) { 104 | result.append( m.getName() ).append( '=' ).append( values.get( m ) ).append( ", " ); 105 | } 106 | // remove last separator: 107 | if ( values.size() > 0 ) { 108 | result.delete( result.length() - 2, result.length() ); 109 | result.append( ")" ); 110 | } 111 | else { 112 | result.delete( result.length() - 1, result.length() ); 113 | } 114 | 115 | return result.toString(); 116 | } 117 | 118 | private SortedSet getRegisteredMethodsInAlphabeticalOrder() { 119 | SortedSet result = new TreeSet( 120 | new Comparator() { 121 | public int compare(Method o1, Method o2) { 122 | return o1.getName().compareTo( o2.getName() ); 123 | } 124 | } 125 | ); 126 | result.addAll( values.keySet() ); 127 | return result; 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/AnnotationReader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection; 6 | 7 | import java.lang.annotation.Annotation; 8 | 9 | /** 10 | * @author Paolo Perrotta 11 | */ 12 | public interface AnnotationReader { 13 | 14 | public T getAnnotation(Class annotationType); 15 | 16 | public boolean isAnnotationPresent(Class annotationType); 17 | 18 | public Annotation[] getAnnotations(); 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/Filter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection; 6 | 7 | /** 8 | * Filter properties 9 | * 10 | * @author Emmanuel Bernard 11 | */ 12 | public interface Filter { 13 | boolean returnStatic(); 14 | 15 | boolean returnTransient(); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/MetadataProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection; 6 | 7 | import java.lang.reflect.AnnotatedElement; 8 | import java.util.Map; 9 | 10 | /** 11 | * Provides metadata 12 | * 13 | * @author Emmanuel Bernard 14 | * @author Sanne Grinovero 15 | */ 16 | public interface MetadataProvider { 17 | 18 | /** 19 | * provide default metadata 20 | */ 21 | Map getDefaults(); 22 | 23 | /** 24 | * provide metadata for a given annotated element 25 | */ 26 | AnnotationReader getAnnotationReader(AnnotatedElement annotatedElement); 27 | 28 | /** 29 | * Reset any internal caches. 30 | * This will free up memory in some implementations, at the cost of 31 | * possibly being a bit slower if its services are needed again. 32 | * Other configuration aspects are not affected. 33 | */ 34 | default void reset() { 35 | //By default a no-op 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/MetadataProviderInjector.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection; 6 | 7 | /** 8 | * Offers access to and the ability to change the metadata provider 9 | * 10 | * @author Emmanuel Bernard 11 | */ 12 | public interface MetadataProviderInjector { 13 | MetadataProvider getMetadataProvider(); 14 | 15 | /** 16 | * Defines the metadata provider for a given Reflection Manager 17 | */ 18 | void setMetadataProvider(MetadataProvider metadataProvider); 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/ReflectionManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection; 6 | 7 | import java.lang.reflect.AnnotatedElement; 8 | import java.lang.reflect.Method; 9 | import java.lang.reflect.Type; 10 | import java.util.Map; 11 | 12 | /** 13 | * The entry point to the reflection layer (a.k.a. the X* layer). 14 | * 15 | * @author Paolo Perrotta 16 | * @author Davide Marchignoli 17 | * @author Sanne Grinovero 18 | */ 19 | public interface ReflectionManager { 20 | 21 | public XClass toXClass(Class clazz); 22 | 23 | public Class toClass(XClass xClazz); 24 | 25 | public Type toType(XClass xClazz); 26 | 27 | public Method toMethod(XMethod method); 28 | 29 | public XPackage toXPackage(Package pkg); 30 | 31 | public boolean equals(XClass class1, Class class2); 32 | 33 | public AnnotationReader buildAnnotationReader(AnnotatedElement annotatedElement); 34 | 35 | public Map getDefaults(); 36 | 37 | /** 38 | * This resets any internal caches. 39 | * This will free up memory in some implementations, at the cost of 40 | * possibly being a bit slower if its services are needed again. 41 | *

42 | * Ideally the ReflectionManager should be discarded after use, 43 | * but sometimes that's not posible. 44 | * This method is intended to be used when there is reasonable 45 | * expectation for te ReflectionManager to no longer be needed, 46 | * while having the option to still use it in case the assumption 47 | * doesn't hold true. 48 | *

49 | *

50 | * Careful: after invoking this method, returned X* instances will 51 | * no longer honour any identity equality contract with X* instances 52 | * which have been returned before resetting the cache. 53 | *

54 | * This operation does not affect the configuration. 55 | */ 56 | default void reset() { 57 | //By default a no-op 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/ReflectionUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection; 6 | 7 | import java.lang.reflect.Field; 8 | import java.lang.reflect.Method; 9 | import java.lang.reflect.Modifier; 10 | import java.lang.reflect.Type; 11 | import org.hibernate.annotations.common.reflection.java.generics.TypeUtils; 12 | 13 | /** 14 | * @author Paolo Perrotta 15 | */ 16 | public class ReflectionUtil { 17 | 18 | public static boolean isProperty(Method m, Type boundType, Filter filter) { 19 | return ReflectionUtil.isPropertyType( boundType ) 20 | && !m.isSynthetic() 21 | && !m.isBridge() 22 | && ( filter.returnStatic() || !Modifier.isStatic( m.getModifiers() ) ) 23 | && m.getParameterCount() == 0 24 | && ( m.getName().startsWith( "get" ) || m.getName().startsWith( "is" ) ); 25 | // TODO should we use stronger checking on the naming of getters/setters, or just leave this to the validator? 26 | } 27 | 28 | public static boolean isProperty(Field f, Type boundType, Filter filter) { 29 | return ( filter.returnStatic() || ! Modifier.isStatic( f.getModifiers() ) ) 30 | && ( filter.returnTransient() || ! Modifier.isTransient( f.getModifiers() ) ) 31 | && !f.isSynthetic() 32 | && ReflectionUtil.isPropertyType( boundType ); 33 | } 34 | 35 | private static boolean isPropertyType(Type type) { 36 | // return TypeUtils.isArray( type ) || TypeUtils.isCollection( type ) || ( TypeUtils.isBase( type ) && ! TypeUtils.isVoid( type ) ); 37 | return !TypeUtils.isVoid( type ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/XAnnotatedElement.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection; 6 | 7 | import java.lang.annotation.Annotation; 8 | 9 | /** 10 | * @author Paolo Perrotta 11 | * @author Davide Marchignoli 12 | */ 13 | public interface XAnnotatedElement { 14 | 15 | T getAnnotation(Class annotationType); 16 | 17 | boolean isAnnotationPresent(Class annotationType); 18 | 19 | Annotation[] getAnnotations(); 20 | 21 | /** 22 | * Returns true if the underlying artefact 23 | * is the same 24 | */ 25 | boolean equals(Object x); 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/XClass.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * @author Paolo Perrotta 11 | * @author Davide Marchignoli 12 | */ 13 | public interface XClass extends XAnnotatedElement { 14 | 15 | public static final String ACCESS_PROPERTY = "property"; 16 | public static final String ACCESS_FIELD = "field"; 17 | public static final String ACCESS_RECORD = "record"; 18 | 19 | static final Filter DEFAULT_FILTER = new Filter() { 20 | 21 | public boolean returnStatic() { 22 | return false; 23 | } 24 | 25 | public boolean returnTransient() { 26 | return false; 27 | } 28 | }; 29 | 30 | String getName(); 31 | 32 | /** 33 | * @see Class#getSuperclass() 34 | */ 35 | XClass getSuperclass(); 36 | 37 | /** 38 | * The containing class or package 39 | */ 40 | XAnnotatedElement getContainingElement(); 41 | 42 | /** 43 | * @see Class#getInterfaces() 44 | */ 45 | XClass[] getInterfaces(); 46 | 47 | /** 48 | * see Class#isInterface() 49 | */ 50 | boolean isInterface(); 51 | 52 | boolean isAbstract(); 53 | 54 | boolean isPrimitive(); 55 | 56 | boolean isEnum(); 57 | 58 | boolean isAssignableFrom(XClass c); 59 | 60 | List getDeclaredProperties(String accessType); 61 | 62 | List getDeclaredProperties(String accessType, Filter filter); 63 | 64 | /** 65 | * Returns the Methods defined by this class. 66 | */ 67 | List getDeclaredMethods(); 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/XMember.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection; 6 | 7 | import java.util.Collection; 8 | 9 | /** 10 | * @author Emmanuel Bernard 11 | */ 12 | public abstract interface XMember extends XAnnotatedElement { 13 | 14 | /** 15 | * Retrieve the XClass reference for the class which declares this member. 16 | * 17 | * @return The XClass representing the declaring class of the underlying member 18 | */ 19 | public XClass getDeclaringClass(); 20 | 21 | String getName(); 22 | 23 | boolean isCollection(); 24 | 25 | boolean isArray(); 26 | 27 | /** 28 | * The collection class for collections, null for others. 29 | */ 30 | Class getCollectionClass(); 31 | 32 | // TODO We should probably try to reduce the following three methods to two. 33 | // the last one is particularly offensive 34 | 35 | /** 36 | * This property's XClass. 37 | */ 38 | XClass getType(); 39 | 40 | /** 41 | * This property's type for simple properties, the type of its elements for arrays and collections. 42 | */ 43 | XClass getElementClass(); 44 | 45 | /** 46 | * The type of this property's elements for arrays, the type of the property itself for everything else. 47 | */ 48 | XClass getClassOrElementClass(); 49 | 50 | /** 51 | * The type of this map's key, or null for anything that is not a map. 52 | */ 53 | XClass getMapKey(); 54 | 55 | /** 56 | * Same modifiers as java.lang.Member#getModifiers() 57 | */ 58 | int getModifiers(); 59 | 60 | //this breaks the Java reflect hierarchy, since accessible belongs to AccessibleObject 61 | void setAccessible(boolean accessible); 62 | 63 | public Object invoke(Object target, Object... parameters); 64 | 65 | /** 66 | * Invoke the method with no parameters. 67 | * Same as {@link #invoke(Object, Object...)}. 68 | * @param target 69 | * @return 70 | */ 71 | public Object invoke(Object target); 72 | 73 | boolean isTypeResolved(); 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/XMethod.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection; 6 | 7 | /** 8 | * Represent an invokable method 9 | *

10 | * The underlying layer does not guaranty that xProperty == xMethod 11 | * if the underlying artefact is the same 12 | * However xProperty.equals(xMethod) is supposed to return true 13 | * 14 | * @author Emmanuel Bernard 15 | */ 16 | public interface XMethod extends XMember { 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/XPackage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection; 6 | 7 | /** 8 | * @author Paolo Perrotta 9 | * @author Davide Marchignoli 10 | */ 11 | public interface XPackage extends XAnnotatedElement { 12 | 13 | String getName(); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/XProperty.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection; 6 | 7 | /** 8 | * A member which actually is a property (as per the JavaBean spec) 9 | * Note that the same underlying artefact can be represented as both 10 | * XProperty and XMethod 11 | * The underlying layer does not guaranty that xProperty == xMethod 12 | * if the underlying artefact is the same 13 | * However xProperty.equals(xMethod) is supposed to return true 14 | * 15 | * @author Paolo Perrotta 16 | * @author Davide Marchignoli 17 | * @author Emmanuel Bernard 18 | */ 19 | public interface XProperty extends XMember { 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/java/JavaAnnotationReader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection.java; 6 | 7 | import java.lang.annotation.Annotation; 8 | import java.lang.reflect.AnnotatedElement; 9 | import org.hibernate.annotations.common.reflection.AnnotationReader; 10 | 11 | /** 12 | * Reads standard Java annotations. 13 | * 14 | * @author Paolo Perrotta 15 | * @author Davide Marchignoli 16 | */ 17 | final class JavaAnnotationReader implements AnnotationReader { 18 | 19 | protected final AnnotatedElement element; 20 | 21 | public JavaAnnotationReader(AnnotatedElement el) { 22 | this.element = el; 23 | } 24 | 25 | public T getAnnotation(Class annotationType) { 26 | return element.getAnnotation( annotationType ); 27 | } 28 | 29 | public boolean isAnnotationPresent(Class annotationType) { 30 | return element.isAnnotationPresent( annotationType ); 31 | } 32 | 33 | public Annotation[] getAnnotations() { 34 | return element.getAnnotations(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/java/JavaMetadataProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection.java; 6 | 7 | import java.lang.reflect.AnnotatedElement; 8 | import java.util.Collections; 9 | import java.util.Map; 10 | import org.hibernate.annotations.common.reflection.AnnotationReader; 11 | import org.hibernate.annotations.common.reflection.MetadataProvider; 12 | 13 | /** 14 | * @author Emmanuel Bernard 15 | */ 16 | public final class JavaMetadataProvider implements MetadataProvider { 17 | 18 | public Map getDefaults() { 19 | return Collections.emptyMap(); 20 | } 21 | 22 | public AnnotationReader getAnnotationReader(AnnotatedElement annotatedElement) { 23 | return new JavaAnnotationReader(annotatedElement); 24 | } 25 | 26 | @Override 27 | public void reset() { 28 | //no-op 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/java/JavaReflectionManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection.java; 6 | 7 | import java.lang.reflect.AnnotatedElement; 8 | import java.lang.reflect.Member; 9 | import java.lang.reflect.Method; 10 | import java.lang.reflect.ParameterizedType; 11 | import java.lang.reflect.Type; 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | import java.util.concurrent.atomic.AtomicBoolean; 15 | import org.hibernate.annotations.common.reflection.AnnotationReader; 16 | import org.hibernate.annotations.common.reflection.MetadataProvider; 17 | import org.hibernate.annotations.common.reflection.MetadataProviderInjector; 18 | import org.hibernate.annotations.common.reflection.ReflectionManager; 19 | import org.hibernate.annotations.common.reflection.XClass; 20 | import org.hibernate.annotations.common.reflection.XMethod; 21 | import org.hibernate.annotations.common.reflection.XPackage; 22 | import org.hibernate.annotations.common.reflection.XProperty; 23 | import org.hibernate.annotations.common.reflection.java.generics.IdentityTypeEnvironment; 24 | import org.hibernate.annotations.common.reflection.java.generics.TypeEnvironment; 25 | import org.hibernate.annotations.common.reflection.java.generics.TypeEnvironmentFactory; 26 | import org.hibernate.annotations.common.reflection.java.generics.TypeSwitch; 27 | import org.hibernate.annotations.common.reflection.java.generics.TypeUtils; 28 | 29 | /** 30 | * The factory for all the objects in this package. 31 | * 32 | * @author Paolo Perrotta 33 | * @author Davide Marchignoli 34 | * @author Emmanuel Bernard 35 | * @author Sanne Grinovero 36 | */ 37 | public final class JavaReflectionManager implements ReflectionManager, MetadataProviderInjector { 38 | 39 | private static final boolean METADATA_CACHE_DIAGNOSTICS = Boolean.getBoolean( "org.hibernate.annotations.common.METADATA_CACHE_DIAGNOSTICS" ); 40 | 41 | private MetadataProvider metadataProvider; 42 | 43 | private final AtomicBoolean empty = new AtomicBoolean(true); 44 | 45 | public MetadataProvider getMetadataProvider() { 46 | if (metadataProvider == null) { 47 | setMetadataProvider( new JavaMetadataProvider() ); 48 | } 49 | return metadataProvider; 50 | } 51 | 52 | public void setMetadataProvider(MetadataProvider metadataProvider) { 53 | this.metadataProvider = metadataProvider; 54 | } 55 | 56 | private final TypeEnvironmentMap xClasses = new TypeEnvironmentMap<>( this::javaXClassConstruction ); 57 | 58 | private JavaXClass javaXClassConstruction( 59 | Class classType, 60 | TypeEnvironment typeEnvironment) { 61 | used(); 62 | return new JavaXClass( classType, typeEnvironment, this ); 63 | } 64 | 65 | private Map packagesToXPackages; 66 | 67 | private final TypeEnvironmentMap xProperties = new TypeEnvironmentMap<>( this::javaXPropertyConstruction ); 68 | 69 | private JavaXProperty javaXPropertyConstruction(Member member, TypeEnvironment typeEnvironment) { 70 | used(); 71 | return JavaXProperty.create( member, typeEnvironment, this ); 72 | } 73 | 74 | private final TypeEnvironmentMap xMethods = new TypeEnvironmentMap<>( this::javaJavaXMethodConstruction ); 75 | 76 | private JavaXMethod javaJavaXMethodConstruction(Member member, TypeEnvironment typeEnvironment) { 77 | used(); 78 | return JavaXMethod.create( member, typeEnvironment, this ); 79 | } 80 | 81 | public XClass toXClass(Class clazz) { 82 | return toXClass( clazz, IdentityTypeEnvironment.INSTANCE ); 83 | } 84 | 85 | public Class toClass(XClass xClazz) { 86 | if ( ! ( xClazz instanceof JavaXClass ) ) { 87 | throw new IllegalArgumentException( "XClass not coming from this ReflectionManager implementation" ); 88 | } 89 | return (Class) ( (JavaXClass) xClazz ).toAnnotatedElement(); 90 | } 91 | 92 | public Method toMethod(XMethod xMethod) { 93 | if ( ! ( xMethod instanceof JavaXMethod ) ) { 94 | throw new IllegalArgumentException( "XMethod not coming from this ReflectionManager implementation" ); 95 | } 96 | return (Method) ( (JavaXAnnotatedElement) xMethod ).toAnnotatedElement(); 97 | } 98 | 99 | XClass toXClass(Type t, final TypeEnvironment context) { 100 | return new TypeSwitch() { 101 | @Override 102 | public XClass caseClass(Class classType) { 103 | return xClasses.getOrCompute( context, classType ); 104 | } 105 | 106 | @Override 107 | public XClass caseParameterizedType(ParameterizedType parameterizedType) { 108 | return toXClass( parameterizedType.getRawType(), 109 | TypeEnvironmentFactory.getEnvironment( parameterizedType, context ) 110 | ); 111 | } 112 | }.doSwitch( context.bind( t ) ); 113 | } 114 | 115 | @Override 116 | public XPackage toXPackage(Package pkg) { 117 | final Map packagesToXPackagesMap = getPackagesToXPackagesMap(); 118 | JavaXPackage xPackage = packagesToXPackagesMap.get( pkg ); 119 | if ( xPackage == null ) { 120 | xPackage = new JavaXPackage( pkg, this ); 121 | used(); 122 | packagesToXPackagesMap.put( pkg, xPackage ); 123 | } 124 | return xPackage; 125 | } 126 | 127 | private Map getPackagesToXPackagesMap() { 128 | if ( this.packagesToXPackages == null ) { 129 | this.packagesToXPackages = new HashMap<>( 8, 0.5f ); 130 | } 131 | return this.packagesToXPackages; 132 | } 133 | 134 | XProperty getXProperty(Member member, TypeEnvironment context) { 135 | return xProperties.getOrCompute( context, member ); 136 | } 137 | 138 | XMethod getXMethod(Member member, TypeEnvironment context) { 139 | return xMethods.getOrCompute( context, member ); 140 | } 141 | 142 | TypeEnvironment getTypeEnvironment(final Type t) { 143 | return new TypeSwitch() { 144 | @Override 145 | public TypeEnvironment caseClass(Class classType) { 146 | return TypeEnvironmentFactory.getEnvironment( classType ); 147 | } 148 | 149 | @Override 150 | public TypeEnvironment caseParameterizedType(ParameterizedType parameterizedType) { 151 | return TypeEnvironmentFactory.getEnvironment( parameterizedType ); 152 | } 153 | 154 | @Override 155 | public TypeEnvironment defaultCase(Type type) { 156 | return IdentityTypeEnvironment.INSTANCE; 157 | } 158 | }.doSwitch( t ); 159 | } 160 | 161 | public JavaXType toXType(TypeEnvironment context, Type propType) { 162 | Type boundType = toApproximatingEnvironment( context ).bind( propType ); 163 | if ( TypeUtils.isArray( boundType ) ) { 164 | return new JavaXArrayType( propType, context, this ); 165 | } 166 | if ( TypeUtils.isCollection( boundType ) ) { 167 | return new JavaXCollectionType( propType, context, this ); 168 | } 169 | if ( TypeUtils.isSimple( boundType ) ) { 170 | return new JavaXSimpleType( propType, context, this ); 171 | } 172 | throw new IllegalArgumentException( "No PropertyTypeExtractor available for type void " ); 173 | } 174 | 175 | @Override 176 | public Type toType(XClass xClazz) { 177 | if ( ! ( xClazz instanceof JavaXClass ) ) { 178 | throw new IllegalArgumentException( "XClass not coming from this ReflectionManager implementation" ); 179 | } 180 | final JavaXClass javaXClazz = (JavaXClass) xClazz; 181 | final Class clazz = javaXClazz.toClass(); 182 | final Type[] typeArguments = clazz.getTypeParameters(); 183 | if ( typeArguments.length == 0 ) { 184 | return clazz; 185 | } 186 | return javaXClazz.getTypeEnvironment().bind( 187 | new ParameterizedType() { 188 | @Override 189 | public Type[] getActualTypeArguments() { 190 | return typeArguments; 191 | } 192 | 193 | @Override 194 | public Type getRawType() { 195 | return clazz; 196 | } 197 | 198 | @Override 199 | public Type getOwnerType() { 200 | return null; 201 | } 202 | } 203 | ); 204 | } 205 | 206 | public boolean equals(XClass class1, Class class2) { 207 | if ( class1 == null ) { 208 | return class2 == null; 209 | } 210 | return ( (JavaXClass) class1 ).toClass().equals( class2 ); 211 | } 212 | 213 | public TypeEnvironment toApproximatingEnvironment(TypeEnvironment context) { 214 | return TypeEnvironmentFactory.toApproximatingEnvironment( context ); 215 | } 216 | 217 | public AnnotationReader buildAnnotationReader(AnnotatedElement annotatedElement) { 218 | return getMetadataProvider().getAnnotationReader( annotatedElement ); 219 | } 220 | 221 | public Map getDefaults() { 222 | return getMetadataProvider().getDefaults(); 223 | } 224 | 225 | @Override 226 | public void reset() { 227 | boolean wasEmpty = empty.getAndSet( true ); 228 | if ( !wasEmpty ) { 229 | this.xClasses.clear(); 230 | this.packagesToXPackages = null; 231 | this.xProperties.clear(); 232 | this.xMethods.clear(); 233 | if ( METADATA_CACHE_DIAGNOSTICS ) { 234 | new RuntimeException( "Diagnostics message : Caches now empty" ).printStackTrace(); 235 | } 236 | } 237 | if ( metadataProvider != null ) { 238 | this.metadataProvider.reset(); 239 | } 240 | } 241 | 242 | private void used() { 243 | boolean wasEmpty = empty.getAndSet( false ); 244 | if ( wasEmpty && METADATA_CACHE_DIAGNOSTICS ) { 245 | new RuntimeException( "Diagnostics message : Caches now being used" ).printStackTrace(); 246 | } 247 | } 248 | 249 | } 250 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/java/JavaXAnnotatedElement.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection.java; 6 | 7 | import java.lang.annotation.Annotation; 8 | import java.lang.reflect.AnnotatedElement; 9 | import org.hibernate.annotations.common.reflection.AnnotationReader; 10 | import org.hibernate.annotations.common.reflection.XAnnotatedElement; 11 | 12 | /** 13 | * @author Paolo Perrotta 14 | * @author Davide Marchignoli 15 | */ 16 | abstract class JavaXAnnotatedElement implements XAnnotatedElement { 17 | 18 | private final JavaReflectionManager factory; 19 | 20 | private final AnnotatedElement annotatedElement; 21 | 22 | public JavaXAnnotatedElement(AnnotatedElement annotatedElement, JavaReflectionManager factory) { 23 | this.factory = factory; 24 | this.annotatedElement = annotatedElement; 25 | } 26 | 27 | protected JavaReflectionManager getFactory() { 28 | return factory; 29 | } 30 | 31 | private AnnotationReader getAnnotationReader() { 32 | return factory.buildAnnotationReader(annotatedElement); 33 | } 34 | 35 | public T getAnnotation(Class annotationType) { 36 | return getAnnotationReader().getAnnotation( annotationType ); 37 | } 38 | 39 | public boolean isAnnotationPresent(Class annotationType) { 40 | return getAnnotationReader().isAnnotationPresent( annotationType ); 41 | } 42 | 43 | public Annotation[] getAnnotations() { 44 | return getAnnotationReader().getAnnotations(); 45 | } 46 | 47 | AnnotatedElement toAnnotatedElement() { 48 | return annotatedElement; 49 | } 50 | 51 | @Override 52 | public boolean equals(Object obj) { 53 | if ( ! ( obj instanceof JavaXAnnotatedElement ) ) return false; 54 | JavaXAnnotatedElement other = (JavaXAnnotatedElement) obj; 55 | //FIXME yuk this defeat the type environment 56 | return annotatedElement.equals( other.toAnnotatedElement() ); 57 | } 58 | 59 | @Override 60 | public int hashCode() { 61 | return annotatedElement.hashCode(); 62 | } 63 | 64 | @Override 65 | public String toString() { 66 | return annotatedElement.toString(); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/java/JavaXArrayType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection.java; 6 | 7 | import java.lang.reflect.Array; 8 | import java.lang.reflect.GenericArrayType; 9 | import java.lang.reflect.Type; 10 | import java.util.Collection; 11 | import org.hibernate.annotations.common.reflection.XClass; 12 | import org.hibernate.annotations.common.reflection.java.generics.TypeEnvironment; 13 | import org.hibernate.annotations.common.reflection.java.generics.TypeSwitch; 14 | 15 | /** 16 | * @author Emmanuel Bernard 17 | * @author Paolo Perrotta 18 | */ 19 | final class JavaXArrayType extends JavaXType { 20 | 21 | public JavaXArrayType(Type type, TypeEnvironment context, JavaReflectionManager factory) { 22 | super( type, context, factory ); 23 | } 24 | 25 | public boolean isArray() { 26 | return true; 27 | } 28 | 29 | public boolean isCollection() { 30 | return false; 31 | } 32 | 33 | public XClass getElementClass() { 34 | return toXClass( getElementType() ); 35 | } 36 | 37 | private Type getElementType() { 38 | //TODO make it a static class for faster performance? 39 | return new TypeSwitch() { 40 | @Override 41 | public Type caseClass(Class classType) { 42 | return classType.getComponentType(); 43 | } 44 | 45 | @Override 46 | public Type caseGenericArrayType(GenericArrayType genericArrayType) { 47 | return genericArrayType.getGenericComponentType(); 48 | } 49 | 50 | @Override 51 | public Type defaultCase(Type t) { 52 | throw new IllegalArgumentException( t + " is not an array type" ); 53 | } 54 | }.doSwitch( approximate() ); 55 | } 56 | 57 | public XClass getClassOrElementClass() { 58 | return getElementClass(); 59 | } 60 | 61 | public Class getCollectionClass() { 62 | return null; 63 | } 64 | 65 | public XClass getMapKey() { 66 | return null; 67 | } 68 | 69 | public XClass getType() { 70 | Type boundType = getElementType(); 71 | if ( boundType instanceof Class ) { 72 | boundType = arrayTypeOf( (Class) boundType ); 73 | } 74 | return toXClass( boundType ); 75 | } 76 | 77 | private Class arrayTypeOf(Class componentType) { 78 | return Array.newInstance( componentType, 0 ).getClass(); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/java/JavaXClass.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection.java; 6 | 7 | import java.lang.reflect.Field; 8 | import java.lang.reflect.Method; 9 | import java.lang.reflect.Modifier; 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | import org.hibernate.annotations.common.reflection.Filter; 13 | import org.hibernate.annotations.common.reflection.ReflectionUtil; 14 | import org.hibernate.annotations.common.reflection.XAnnotatedElement; 15 | import org.hibernate.annotations.common.reflection.XClass; 16 | import org.hibernate.annotations.common.reflection.XMethod; 17 | import org.hibernate.annotations.common.reflection.XProperty; 18 | import org.hibernate.annotations.common.reflection.java.generics.CompoundTypeEnvironment; 19 | import org.hibernate.annotations.common.reflection.java.generics.TypeEnvironment; 20 | 21 | /** 22 | * @author Paolo Perrotta 23 | * @author Davide Marchignoli 24 | */ 25 | final class JavaXClass extends JavaXAnnotatedElement implements XClass { 26 | 27 | private static final Class RECORD_CLASS; 28 | private static final Method GET_RECORD_COMPONENTS; 29 | private static final Method GET_ACCESSOR; 30 | 31 | static { 32 | Class recordClass = null; 33 | Method getRecordComponents = null; 34 | Method getAccessor = null; 35 | 36 | try { 37 | recordClass = Class.forName( "java.lang.Record" ); 38 | getRecordComponents = Class.class.getMethod( "getRecordComponents" ); 39 | final Class recordComponentClass = Class.forName( "java.lang.reflect.RecordComponent" ); 40 | getAccessor = recordComponentClass.getMethod( "getAccessor" ); 41 | } 42 | catch (Exception e) { 43 | // Ignore 44 | } 45 | RECORD_CLASS = recordClass; 46 | GET_RECORD_COMPONENTS = getRecordComponents; 47 | GET_ACCESSOR = getAccessor; 48 | } 49 | 50 | private final TypeEnvironment context; 51 | private final Class clazz; 52 | 53 | public JavaXClass(Class clazz, TypeEnvironment env, JavaReflectionManager factory) { 54 | super( clazz, factory ); 55 | this.clazz = clazz; //optimization 56 | this.context = env; 57 | } 58 | 59 | public String getName() { 60 | return toClass().getName(); 61 | } 62 | 63 | public XClass getSuperclass() { 64 | return getFactory().toXClass( toClass().getSuperclass(), 65 | CompoundTypeEnvironment.create( 66 | getTypeEnvironment(), 67 | getFactory().getTypeEnvironment( toClass() ) 68 | ) 69 | ); 70 | } 71 | 72 | @Override 73 | public XAnnotatedElement getContainingElement() { 74 | Class enclosingClass = toClass().getEnclosingClass(); 75 | if ( enclosingClass != null ) { 76 | return getFactory().toXClass( enclosingClass, 77 | CompoundTypeEnvironment.create( 78 | getTypeEnvironment(), 79 | getFactory().getTypeEnvironment( toClass() ) 80 | ) 81 | ); 82 | } 83 | else { 84 | return getFactory().toXPackage( toClass().getPackage() ); 85 | } 86 | } 87 | 88 | public XClass[] getInterfaces() { 89 | Class[] classes = toClass().getInterfaces(); 90 | int length = classes.length; 91 | XClass[] xClasses = new XClass[length]; 92 | if (length != 0) { 93 | TypeEnvironment environment = CompoundTypeEnvironment.create( 94 | getTypeEnvironment(), 95 | getFactory().getTypeEnvironment( toClass() ) 96 | ); 97 | for ( int index = 0; index < length ; index++ ) { 98 | xClasses[index] = getFactory().toXClass( classes[index], environment ); 99 | } 100 | } 101 | return xClasses; 102 | } 103 | 104 | public boolean isInterface() { 105 | return toClass().isInterface(); 106 | } 107 | 108 | public boolean isAbstract() { 109 | return Modifier.isAbstract( toClass().getModifiers() ); 110 | } 111 | 112 | public boolean isPrimitive() { 113 | return toClass().isPrimitive(); 114 | } 115 | 116 | public boolean isEnum() { 117 | return toClass().isEnum(); 118 | } 119 | 120 | private List getDeclaredFieldProperties(Filter filter) { 121 | Field[] declaredFields = toClass().getDeclaredFields(); 122 | ArrayList result = new ArrayList<>(); 123 | for ( Field f : declaredFields ) { 124 | if ( ReflectionUtil.isProperty( f, getTypeEnvironment().bind( f.getGenericType() ), filter ) ) { 125 | result.add( getFactory().getXProperty( f, getTypeEnvironment() ) ); 126 | } 127 | } 128 | result.trimToSize(); 129 | return result; 130 | } 131 | 132 | private List getDeclaredMethodProperties(Filter filter) { 133 | ArrayList result = new ArrayList(); 134 | Method[] declaredMethods = toClass().getDeclaredMethods(); 135 | for ( Method m : declaredMethods ) { 136 | if ( ReflectionUtil.isProperty( m, getTypeEnvironment().bind( m.getGenericReturnType() ), filter ) ) { 137 | result.add( getFactory().getXProperty( m, getTypeEnvironment() ) ); 138 | } 139 | } 140 | result.trimToSize(); 141 | return result; 142 | } 143 | 144 | private List getDeclaredComponentProperties(Filter filter) { 145 | ArrayList result = new ArrayList(); 146 | Class javaClass = toClass(); 147 | if ( RECORD_CLASS == null || !RECORD_CLASS.isAssignableFrom( javaClass ) ) { 148 | return result; 149 | } 150 | try { 151 | Object[] declaredComponents = (Object[]) GET_RECORD_COMPONENTS.invoke(javaClass); 152 | for ( Object component : declaredComponents ) { 153 | Method accessor = (Method) GET_ACCESSOR.invoke(component ); 154 | result.add( getFactory().getXProperty( accessor, getTypeEnvironment() ) ); 155 | } 156 | } catch (Exception e) { 157 | throw new RuntimeException( "Could not access record components", e ); 158 | } 159 | result.trimToSize(); 160 | return result; 161 | } 162 | 163 | public List getDeclaredProperties(String accessType) { 164 | return getDeclaredProperties( accessType, XClass.DEFAULT_FILTER ); 165 | } 166 | 167 | public List getDeclaredProperties(String accessType, Filter filter) { 168 | if ( accessType.equals( ACCESS_FIELD ) ) { 169 | return getDeclaredFieldProperties( filter ); 170 | } 171 | if ( accessType.equals( ACCESS_PROPERTY ) ) { 172 | return getDeclaredMethodProperties( filter ); 173 | } 174 | if ( accessType.equals( ACCESS_RECORD ) ) { 175 | return getDeclaredComponentProperties( filter ); 176 | } 177 | throw new IllegalArgumentException( "Unknown access type " + accessType ); 178 | } 179 | 180 | public List getDeclaredMethods() { 181 | Method[] declaredMethods = toClass().getDeclaredMethods(); 182 | List result = new ArrayList<>( declaredMethods.length ); 183 | for ( Method m : declaredMethods ) { 184 | result.add( getFactory().getXMethod( m, getTypeEnvironment() ) ); 185 | } 186 | return result; 187 | } 188 | 189 | public Class toClass() { 190 | return clazz; 191 | } 192 | 193 | public boolean isAssignableFrom(XClass c) { 194 | return toClass().isAssignableFrom( ( (JavaXClass) c ).toClass() ); 195 | } 196 | 197 | boolean isArray() { 198 | return toClass().isArray(); 199 | } 200 | 201 | TypeEnvironment getTypeEnvironment() { 202 | return context; 203 | } 204 | 205 | @Override 206 | public String toString() { 207 | return getName(); 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/java/JavaXCollectionType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection.java; 6 | 7 | import java.lang.reflect.ParameterizedType; 8 | import java.lang.reflect.Type; 9 | import java.util.Collection; 10 | import java.util.Map; 11 | import java.util.SortedMap; 12 | import org.hibernate.annotations.common.reflection.XClass; 13 | import org.hibernate.annotations.common.reflection.java.generics.TypeEnvironment; 14 | import org.hibernate.annotations.common.reflection.java.generics.TypeSwitch; 15 | import org.hibernate.annotations.common.reflection.java.generics.TypeUtils; 16 | 17 | /** 18 | * @author Emmanuel Bernard 19 | * @author Paolo Perrotta 20 | */ 21 | @SuppressWarnings("unchecked") 22 | final class JavaXCollectionType extends JavaXType { 23 | 24 | public JavaXCollectionType(Type type, TypeEnvironment context, JavaReflectionManager factory) { 25 | super( type, context, factory ); 26 | } 27 | 28 | public boolean isArray() { 29 | return false; 30 | } 31 | 32 | public boolean isCollection() { 33 | return true; 34 | } 35 | 36 | public XClass getElementClass() { 37 | return new TypeSwitch() { 38 | @Override 39 | public XClass caseParameterizedType(ParameterizedType parameterizedType) { 40 | Type[] args = parameterizedType.getActualTypeArguments(); 41 | Type componentType; 42 | Class collectionClass = getCollectionClass(); 43 | if ( Map.class.isAssignableFrom( collectionClass ) 44 | || SortedMap.class.isAssignableFrom( collectionClass ) ) { 45 | componentType = args[1]; 46 | } 47 | else { 48 | componentType = args[0]; 49 | } 50 | return toXClass( componentType ); 51 | } 52 | }.doSwitch( approximate() ); 53 | } 54 | 55 | public XClass getMapKey() { 56 | return new TypeSwitch() { 57 | @Override 58 | public XClass caseParameterizedType(ParameterizedType parameterizedType) { 59 | if ( Map.class.isAssignableFrom( getCollectionClass() ) ) { 60 | return toXClass( parameterizedType.getActualTypeArguments()[0] ); 61 | } 62 | return null; 63 | } 64 | }.doSwitch( approximate() ); 65 | } 66 | 67 | public XClass getClassOrElementClass() { 68 | return toXClass( approximate() ); 69 | } 70 | 71 | public Class getCollectionClass() { 72 | return TypeUtils.getCollectionClass( approximate() ); 73 | } 74 | 75 | public XClass getType() { 76 | return toXClass( approximate() ); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/java/JavaXMember.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection.java; 6 | 7 | import java.lang.reflect.AccessibleObject; 8 | import java.lang.reflect.AnnotatedElement; 9 | import java.lang.reflect.Field; 10 | import java.lang.reflect.Member; 11 | import java.lang.reflect.Method; 12 | import java.lang.reflect.Type; 13 | import java.util.Collection; 14 | import org.hibernate.annotations.common.reflection.XClass; 15 | import org.hibernate.annotations.common.reflection.XMember; 16 | import org.hibernate.annotations.common.reflection.java.generics.TypeEnvironment; 17 | 18 | /** 19 | * @author Emmanuel Bernard 20 | */ 21 | public abstract class JavaXMember extends JavaXAnnotatedElement implements XMember { 22 | private final Type type; 23 | private final TypeEnvironment env; 24 | private final JavaXType xType; 25 | 26 | protected static Type typeOf(Member member, TypeEnvironment env) { 27 | if ( member instanceof Field ) { 28 | return env.bind( ( (Field) member ).getGenericType() ); 29 | } 30 | if ( member instanceof Method ) { 31 | return env.bind( ( (Method) member ).getGenericReturnType() ); 32 | } 33 | throw new IllegalArgumentException( "Member " + member + " is neither a field nor a method" ); 34 | } 35 | 36 | protected JavaXMember(Member member, Type type, TypeEnvironment env, JavaReflectionManager factory, JavaXType xType) { 37 | super( (AnnotatedElement) member, factory ); 38 | this.type = type; 39 | this.env = env; 40 | this.xType = xType; 41 | } 42 | 43 | public XClass getType() { 44 | return xType.getType(); 45 | } 46 | 47 | public abstract String getName(); 48 | 49 | public Type getJavaType() { 50 | return env.bind( type ); 51 | } 52 | 53 | protected TypeEnvironment getTypeEnvironment() { 54 | return env; 55 | } 56 | 57 | public Member getMember() { 58 | return (Member) toAnnotatedElement(); 59 | } 60 | 61 | @Override 62 | public XClass getDeclaringClass() { 63 | return getFactory().toXClass( getMember().getDeclaringClass() ); 64 | } 65 | 66 | public Class getCollectionClass() { 67 | return xType.getCollectionClass(); 68 | } 69 | 70 | public XClass getClassOrElementClass() { 71 | return xType.getClassOrElementClass(); 72 | } 73 | 74 | public XClass getElementClass() { 75 | return xType.getElementClass(); 76 | } 77 | 78 | public XClass getMapKey() { 79 | return xType.getMapKey(); 80 | } 81 | 82 | public boolean isArray() { 83 | return xType.isArray(); 84 | } 85 | 86 | public boolean isCollection() { 87 | return xType.isCollection(); 88 | } 89 | 90 | public int getModifiers() { 91 | return getMember().getModifiers(); 92 | } 93 | 94 | public final boolean isTypeResolved() { 95 | return xType.isResolved(); 96 | } 97 | 98 | public void setAccessible(boolean accessible) { 99 | ( (AccessibleObject) getMember() ).setAccessible( accessible ); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/java/JavaXMethod.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection.java; 6 | 7 | import java.lang.reflect.Member; 8 | import java.lang.reflect.Method; 9 | import java.lang.reflect.Type; 10 | import org.hibernate.annotations.common.reflection.XMethod; 11 | import org.hibernate.annotations.common.reflection.java.generics.TypeEnvironment; 12 | 13 | /** 14 | * @author Emmanuel Bernard 15 | */ 16 | final public class JavaXMethod extends JavaXMember implements XMethod { 17 | 18 | private static final Object[] EMPTY_ARRAY = new Object[0]; 19 | 20 | static JavaXMethod create(Member member, TypeEnvironment context, JavaReflectionManager factory) { 21 | final Type propType = typeOf( member, context ); 22 | JavaXType xType = factory.toXType( context, propType ); 23 | return new JavaXMethod( member, propType, context, factory, xType ); 24 | } 25 | 26 | private JavaXMethod(Member member, Type type, TypeEnvironment env, JavaReflectionManager factory, JavaXType xType) { 27 | super( member, type, env, factory, xType ); 28 | assert member instanceof Method; 29 | } 30 | 31 | @Override 32 | public String getName() { 33 | return getMember().getName(); 34 | } 35 | 36 | @Override 37 | public Object invoke(Object target) { 38 | return invoke( target, EMPTY_ARRAY ); 39 | } 40 | 41 | @Override 42 | public Object invoke(Object target, Object... parameters) { 43 | try { 44 | return ( (Method) getMember() ).invoke( target, parameters ); 45 | } 46 | catch (NullPointerException e) { 47 | throw new IllegalArgumentException( "Invoking " + getName() + " on a null object", e ); 48 | } 49 | catch (IllegalArgumentException e) { 50 | throw new IllegalArgumentException( "Invoking " + getName() + " with wrong parameters", e ); 51 | } 52 | catch (Exception e) { 53 | throw new IllegalStateException( "Unable to invoke " + getName(), e ); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/java/JavaXPackage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection.java; 6 | 7 | import org.hibernate.annotations.common.reflection.XPackage; 8 | 9 | /** 10 | * @author Paolo Perrotta 11 | * @author Davide Marchignoli 12 | */ 13 | final class JavaXPackage extends JavaXAnnotatedElement implements XPackage { 14 | 15 | public JavaXPackage(Package pkg, JavaReflectionManager factory) { 16 | super( pkg, factory ); 17 | } 18 | 19 | public String getName() { 20 | return ( (Package) toAnnotatedElement() ).getName(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/java/JavaXProperty.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection.java; 6 | 7 | import java.lang.reflect.Field; 8 | import java.lang.reflect.Member; 9 | import java.lang.reflect.Method; 10 | import java.lang.reflect.Type; 11 | import org.hibernate.annotations.common.reflection.XProperty; 12 | import org.hibernate.annotations.common.reflection.java.generics.TypeEnvironment; 13 | 14 | /** 15 | * @author Paolo Perrotta 16 | * @author Davide Marchignoli 17 | */ 18 | final class JavaXProperty extends JavaXMember implements XProperty { 19 | 20 | private static final Object[] EMPTY_ARRAY = new Object[0]; 21 | private static final Class RECORD_CLASS; 22 | 23 | static { 24 | Class recordClass = null; 25 | 26 | try { 27 | recordClass = Class.forName( "java.lang.Record" ); 28 | } 29 | catch (Exception e) { 30 | // Ignore 31 | } 32 | RECORD_CLASS = recordClass; 33 | } 34 | 35 | static JavaXProperty create(Member member, final TypeEnvironment context, final JavaReflectionManager factory) { 36 | final Type propType = typeOf( member, context ); 37 | JavaXType xType = factory.toXType( context, propType ); 38 | return new JavaXProperty( member, propType, context, factory, xType ); 39 | } 40 | 41 | private JavaXProperty(Member member, Type type, TypeEnvironment env, JavaReflectionManager factory, JavaXType xType) { 42 | super( member, type, env, factory, xType ); 43 | assert member instanceof Field || member instanceof Method; 44 | } 45 | 46 | public String getName() { 47 | String fullName = getMember().getName(); 48 | if ( getMember() instanceof Method ) { 49 | if ( fullName.startsWith( "get" ) ) { 50 | return decapitalize( fullName.substring( "get".length() ) ); 51 | } 52 | if ( fullName.startsWith( "is" ) ) { 53 | return decapitalize( fullName.substring( "is".length() ) ); 54 | } 55 | // If the declaring class is a record, we return the record component name as property name 56 | if ( RECORD_CLASS == null || !RECORD_CLASS.isAssignableFrom( getMember().getDeclaringClass() ) ) { 57 | throw new RuntimeException( "Method " + fullName + " is not a property getter" ); 58 | } 59 | return fullName; 60 | } 61 | else { 62 | return fullName; 63 | } 64 | } 65 | 66 | // See conventions expressed by https://docs.oracle.com/javase/7/docs/api/java/beans/Introspector.html#decapitalize(java.lang.String) 67 | private static String decapitalize(String name) { 68 | if (name != null && name.length() != 0) { 69 | if (name.length() > 1 && Character.isUpperCase(name.charAt(1))) { 70 | return name; 71 | } else { 72 | char[] chars = name.toCharArray(); 73 | chars[0] = Character.toLowerCase(chars[0]); 74 | return new String(chars); 75 | } 76 | } else { 77 | return name; 78 | } 79 | } 80 | 81 | @Override 82 | public Object invoke(Object target) { 83 | //Implementation note: only #invoke(Object target, Object... parameters) 84 | //existed until HCANN 5.0.0.Final, but it turned out to be a performance issue as that would cause 85 | //each invocation to allocate an empty array to pass as vararg. 86 | try { 87 | if ( getMember() instanceof Method ) { 88 | return ( (Method) getMember() ).invoke( target, EMPTY_ARRAY ); 89 | } 90 | else { 91 | return ( (Field) getMember() ).get( target ); 92 | } 93 | } 94 | catch (NullPointerException e) { 95 | throw new IllegalArgumentException( "Invoking " + getName() + " on a null object", e ); 96 | } 97 | catch (IllegalArgumentException e) { 98 | throw new IllegalArgumentException( "Invoking " + getName() + " with wrong parameters", e ); 99 | } 100 | catch (Exception e) { 101 | throw new IllegalStateException( "Unable to invoke " + getName(), e ); 102 | } 103 | } 104 | 105 | @Override 106 | public Object invoke(Object target, Object... parameters) { 107 | if ( parameters.length != 0 ) { 108 | throw new IllegalArgumentException( "An XProperty cannot have invoke parameters" ); 109 | } 110 | return invoke( target ); 111 | } 112 | 113 | @Override 114 | public String toString() { 115 | return getName(); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/java/JavaXSimpleType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection.java; 6 | 7 | import java.lang.reflect.Type; 8 | import java.util.Collection; 9 | import org.hibernate.annotations.common.reflection.XClass; 10 | import org.hibernate.annotations.common.reflection.java.generics.TypeEnvironment; 11 | 12 | /** 13 | * @author Emmanuel Bernard 14 | * @author Paolo Perrotta 15 | */ 16 | final class JavaXSimpleType extends JavaXType { 17 | 18 | public JavaXSimpleType(Type type, TypeEnvironment context, JavaReflectionManager factory) { 19 | super( type, context, factory ); 20 | } 21 | 22 | public boolean isArray() { 23 | return false; 24 | } 25 | 26 | public boolean isCollection() { 27 | return false; 28 | } 29 | 30 | public XClass getElementClass() { 31 | return toXClass( approximate() ); 32 | } 33 | 34 | public XClass getClassOrElementClass() { 35 | return getElementClass(); 36 | } 37 | 38 | public Class getCollectionClass() { 39 | return null; 40 | } 41 | 42 | public XClass getType() { 43 | return toXClass( approximate() ); 44 | } 45 | 46 | public XClass getMapKey() { 47 | return null; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/java/JavaXType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection.java; 6 | 7 | import java.lang.reflect.Type; 8 | import java.util.Collection; 9 | import org.hibernate.annotations.common.reflection.XClass; 10 | import org.hibernate.annotations.common.reflection.java.generics.TypeEnvironment; 11 | import org.hibernate.annotations.common.reflection.java.generics.TypeUtils; 12 | 13 | /** 14 | * The Java X-layer equivalent to a Java Type. 15 | * 16 | * @author Emmanuel Bernard 17 | * @author Paolo Perrotta 18 | */ 19 | abstract class JavaXType { 20 | 21 | private final TypeEnvironment context; 22 | private final JavaReflectionManager factory; 23 | private final Type approximatedType; 24 | private final Type boundType; 25 | 26 | protected JavaXType(Type unboundType, TypeEnvironment context, JavaReflectionManager factory) { 27 | this.context = context; 28 | this.factory = factory; 29 | this.boundType = context.bind( unboundType ); 30 | this.approximatedType = factory.toApproximatingEnvironment( context ).bind( unboundType ); 31 | } 32 | 33 | abstract public boolean isArray(); 34 | 35 | abstract public boolean isCollection(); 36 | 37 | abstract public XClass getElementClass(); 38 | 39 | abstract public XClass getClassOrElementClass(); 40 | 41 | abstract public Class getCollectionClass(); 42 | 43 | abstract public XClass getMapKey(); 44 | 45 | abstract public XClass getType(); 46 | 47 | public boolean isResolved() { 48 | return TypeUtils.isResolved( boundType ); 49 | } 50 | 51 | protected Type approximate() { 52 | return approximatedType; 53 | } 54 | 55 | protected XClass toXClass(Type type) { 56 | return factory.toXClass( type, context ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/java/TypeEnvironmentMap.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection.java; 6 | 7 | import java.util.HashMap; 8 | import java.util.Objects; 9 | import org.hibernate.annotations.common.reflection.java.generics.TypeEnvironment; 10 | 11 | /** 12 | * We need a two-level sparse tree for best efficiency in this case; 13 | * the first split uses TypeEnvironment as a key, under which we store 14 | * an additional Map to further organize by K. 15 | * This used to be implemented as a HashMap with a composite key {TypeEnvironment,K}, 16 | * but this wasn't memory efficient as all composite keys take too much space: 17 | * the nested structure has some overhead as well, but has been shown to cost less 18 | * overall. 19 | * In addition, we strife to not need to compute hashkeys multiple times while 20 | * not needing to allocate stateful lambdas; for this reason the tree nodes 21 | * need to store some additional references. 22 | * 23 | * @param 24 | * @param 25 | * @author Sanne Grinovero 26 | */ 27 | final class TypeEnvironmentMap { 28 | 29 | //First level is optimised for fast access; it's expected to be small so a low load factor 30 | //should be fine in terms of memory costs. 31 | private HashMap rootMap; 32 | private final XTypeConstruction constructionMethod; 33 | 34 | TypeEnvironmentMap(final XTypeConstruction constructionMethod) { 35 | Objects.requireNonNull( constructionMethod ); 36 | this.constructionMethod = constructionMethod; 37 | } 38 | 39 | private HashMap getOrInitRootMap() { 40 | if ( this.rootMap == null ) { 41 | this.rootMap = new HashMap<>( 8, 0.5f ); 42 | } 43 | return this.rootMap; 44 | } 45 | 46 | V getOrCompute(final TypeEnvironment context, final K subKey) { 47 | final ContextScope contextualMap = getOrInitRootMap().computeIfAbsent( context, ContextScope::new ); 48 | return contextualMap.getOrCompute( subKey ); 49 | } 50 | 51 | void clear() { 52 | final HashMap m = this.rootMap; 53 | if ( m != null ) { 54 | // Remove the reference to the rootMap, as very large arrays within HashMap 55 | // are not resized when clearing. 56 | this.rootMap = null; 57 | m.clear(); 58 | } 59 | } 60 | 61 | private final class ContextScope extends HashMap { 62 | 63 | private final TypeEnvironment context; 64 | 65 | private ContextScope(TypeEnvironment context) { 66 | //In the second level of the tree we expect many entries, but we can't have it consume too much memory: 67 | super( 64, 0.85f ); 68 | this.context = context; 69 | } 70 | 71 | private V getOrCompute(K subKey) { 72 | return computeIfAbsent( subKey, this::buildObject ); 73 | } 74 | 75 | private V buildObject(K subKey) { 76 | return constructionMethod.createInstance( subKey, context ); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/java/XTypeConstruction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection.java; 6 | 7 | import org.hibernate.annotations.common.reflection.java.generics.TypeEnvironment; 8 | 9 | @FunctionalInterface 10 | interface XTypeConstruction { 11 | 12 | V createInstance(K typeKey, TypeEnvironment context); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/java/generics/ApproximatingTypeEnvironment.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection.java.generics; 6 | 7 | import java.lang.reflect.Array; 8 | import java.lang.reflect.GenericArrayType; 9 | import java.lang.reflect.ParameterizedType; 10 | import java.lang.reflect.Type; 11 | import java.lang.reflect.TypeVariable; 12 | import java.lang.reflect.WildcardType; 13 | 14 | /** 15 | * A TypeEnvironment that approximates the unresolved components of a generic simple 16 | * type or collection to their nearest upper binding. The returned type is always fully resolved. 17 | *

18 | * The concept of "type approximation" is not really sound in general. This class just does what we need 19 | * within the Hibernate Annotations environment. It's more or less a hack. The idea is that certain 20 | * types can provide useful information even if they're not fully resolved in the environment. This class 21 | * tries to turn those types into the nearest fully resolved type that still carries that information. 22 | *

23 | * For example:
24 | * T becomes Object.
25 | * T extends Foo becomes Foo.
26 | * List<T> becomes List<Object>.
27 | * List<T extends Foo> becomes List<Foo>.
28 | * An array of T extends Foo becomes an array of Foo.

29 | *

30 | * If a type variable has multiple upper bounds, it will be approximated to Object. 31 | * Lower bounds are ignored.

32 | *

33 | * Wildcards are generally not approximated. Class<?> stays Class<?>. 34 | * A wildcard within a generic collection is approximated to its upper binding. List<?> becomes 35 | * List<Object>

36 | *

37 | * Note that Class<T> is not approximated Class<Object>. 38 | * That would be wrong in any situation. All parametric types that are not type variables, collections or 39 | * arrays are coarsely approximated to Object.class. 40 | * 41 | * @author Paolo Perrotta 42 | * @return a type where the generic arguments have been replaced by raw classes. 43 | */ 44 | final class ApproximatingTypeEnvironment implements TypeEnvironment { 45 | 46 | public Type bind(final Type type) { 47 | Type result = fineApproximation( type ); 48 | assert TypeUtils.isResolved( result ); 49 | return result; 50 | } 51 | 52 | private Type fineApproximation(final Type type) { 53 | return new TypeSwitch() { 54 | public Type caseWildcardType(WildcardType wildcardType) { 55 | return wildcardType; 56 | } 57 | 58 | @Override 59 | public Type caseClass(Class classType) { 60 | return classType; 61 | } 62 | 63 | @Override 64 | public Type caseGenericArrayType(GenericArrayType genericArrayType) { 65 | if ( TypeUtils.isResolved( genericArrayType ) ) { 66 | return genericArrayType; 67 | } 68 | Type componentType = genericArrayType.getGenericComponentType(); 69 | Type boundComponentType = bind( componentType ); 70 | if ( boundComponentType instanceof Class ) { 71 | return Array.newInstance( (Class) boundComponentType, 0 ).getClass(); 72 | } 73 | // fall back to coarse approximation, because I found no standard way 74 | // to instance arrays of a generic type 75 | return Object[].class; 76 | } 77 | 78 | @Override 79 | public Type caseParameterizedType(ParameterizedType parameterizedType) { 80 | if ( TypeUtils.isResolved( parameterizedType ) ) { 81 | return parameterizedType; 82 | } 83 | 84 | if ( !TypeUtils.isCollection( parameterizedType ) ) { 85 | return Object.class; // fall back to coarse approximation 86 | } 87 | 88 | Type[] typeArguments = parameterizedType.getActualTypeArguments(); 89 | Type[] approximatedTypeArguments = new Type[typeArguments.length]; 90 | for ( int i = 0; i < typeArguments.length ; i++ ) { 91 | approximatedTypeArguments[i] = coarseApproximation( typeArguments[i] ); 92 | } 93 | 94 | return new ParameterizedTypeImpl( 95 | bind( parameterizedType.getRawType() ), 96 | approximatedTypeArguments, 97 | parameterizedType.getOwnerType() 98 | ); 99 | } 100 | 101 | @Override 102 | public Type defaultCase(Type t) { 103 | return coarseApproximation( t ); 104 | } 105 | }.doSwitch( type ); 106 | } 107 | 108 | private Type coarseApproximation(final Type type) { 109 | Type result = new TypeSwitch() { 110 | public Type caseWildcardType(WildcardType wildcardType) { 111 | return approximateTo( wildcardType.getUpperBounds() ); 112 | } 113 | 114 | @Override 115 | public Type caseGenericArrayType(GenericArrayType genericArrayType) { 116 | if ( TypeUtils.isResolved( genericArrayType ) ) { 117 | return genericArrayType; 118 | } 119 | return Object[].class; 120 | } 121 | 122 | @Override 123 | public Type caseParameterizedType(ParameterizedType parameterizedType) { 124 | if ( TypeUtils.isResolved( parameterizedType ) ) { 125 | return parameterizedType; 126 | } 127 | return parameterizedType.getRawType(); 128 | } 129 | 130 | @Override 131 | public Type caseTypeVariable(TypeVariable typeVariable) { 132 | return approximateTo( typeVariable.getBounds() ); 133 | } 134 | 135 | private Type approximateTo(Type[] bounds) { 136 | return coarseApproximation( bounds[0] ); 137 | } 138 | 139 | @Override 140 | public Type defaultCase(Type t) { 141 | return t; 142 | } 143 | }.doSwitch( type ); 144 | assert TypeUtils.isResolved( result ); 145 | return result; 146 | } 147 | 148 | @Override 149 | public String toString() { 150 | return "approximated_types"; 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/java/generics/CompoundTypeEnvironment.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection.java.generics; 6 | 7 | import java.lang.reflect.Type; 8 | 9 | /** 10 | * A composition of two TypeEnvironment functions. 11 | * 12 | * @author Davide Marchignoli 13 | * @author Paolo Perrotta 14 | */ 15 | public final class CompoundTypeEnvironment implements TypeEnvironment { 16 | 17 | private final TypeEnvironment f; 18 | private final TypeEnvironment g; 19 | private final int hashCode; 20 | 21 | public static TypeEnvironment create(TypeEnvironment f, TypeEnvironment g) { 22 | if ( g == IdentityTypeEnvironment.INSTANCE ) 23 | return f; 24 | if ( f == IdentityTypeEnvironment.INSTANCE ) 25 | return g; 26 | return new CompoundTypeEnvironment( f, g ); 27 | } 28 | 29 | private CompoundTypeEnvironment(TypeEnvironment f, TypeEnvironment g) { 30 | this.f = f; 31 | this.g = g; 32 | this.hashCode = doHashCode( f, g ); 33 | } 34 | 35 | public Type bind(Type type) { 36 | return f.bind( g.bind( type ) ); 37 | } 38 | 39 | public boolean equals(Object o) { 40 | if ( this == o ) return true; 41 | if ( ! ( o instanceof CompoundTypeEnvironment ) ) return false; 42 | 43 | final CompoundTypeEnvironment that = (CompoundTypeEnvironment) o; 44 | 45 | if ( differentHashCode( that ) ) return false; 46 | 47 | if ( !f.equals( that.f ) ) return false; 48 | return g.equals( that.g ); 49 | } 50 | 51 | private boolean differentHashCode(CompoundTypeEnvironment that) { 52 | return hashCode != that.hashCode; 53 | } 54 | 55 | private static int doHashCode( 56 | TypeEnvironment f, 57 | TypeEnvironment g) { 58 | int result; 59 | result = f.hashCode(); 60 | result = 29 * result + g.hashCode(); 61 | return result; 62 | } 63 | 64 | public int hashCode() { 65 | //cached because the inheritance can be big 66 | return hashCode; 67 | } 68 | 69 | @Override 70 | public String toString() { 71 | return f.toString() + "(" + g.toString() + ")"; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/java/generics/GenericArrayTypeImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection.java.generics; 6 | 7 | import java.lang.reflect.GenericArrayType; 8 | import java.lang.reflect.Type; 9 | import java.util.Objects; 10 | 11 | public class GenericArrayTypeImpl implements GenericArrayType { 12 | 13 | private final Type componentType; 14 | 15 | public GenericArrayTypeImpl(Type componentType) { 16 | this.componentType = componentType; 17 | } 18 | 19 | public Type getGenericComponentType() { 20 | return componentType; 21 | } 22 | 23 | @Override 24 | public boolean equals(Object obj) { 25 | if (!(obj instanceof GenericArrayType)) { 26 | return false; 27 | } 28 | GenericArrayType other = (GenericArrayType) obj; 29 | return Objects.equals(getGenericComponentType(), other.getGenericComponentType()); 30 | } 31 | 32 | @Override 33 | public int hashCode() { 34 | return Objects.hashCode(getGenericComponentType()); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/java/generics/IdentityTypeEnvironment.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection.java.generics; 6 | 7 | import java.lang.reflect.Type; 8 | 9 | /** 10 | * Substitutes a Type for itself. 11 | * 12 | * @author Davide Marchignoli 13 | * @author Paolo Perrotta 14 | */ 15 | public final class IdentityTypeEnvironment implements TypeEnvironment { 16 | 17 | public static final TypeEnvironment INSTANCE = new IdentityTypeEnvironment(); 18 | 19 | private IdentityTypeEnvironment() { 20 | } 21 | 22 | public Type bind(Type type) { 23 | return type; 24 | } 25 | 26 | public String toString() { 27 | return "{}"; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/java/generics/ParameterizedTypeImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection.java.generics; 6 | 7 | import java.lang.reflect.ParameterizedType; 8 | import java.lang.reflect.Type; 9 | import java.util.Arrays; 10 | import java.util.Objects; 11 | import java.util.StringJoiner; 12 | 13 | public class ParameterizedTypeImpl implements ParameterizedType { 14 | 15 | private final Type[] substTypeArgs; 16 | private final Type rawType; 17 | private final Type ownerType; 18 | 19 | public ParameterizedTypeImpl(Type rawType, Type[] substTypeArgs, Type ownerType) { 20 | this.substTypeArgs = substTypeArgs; 21 | this.rawType = rawType; 22 | this.ownerType = ownerType; 23 | } 24 | 25 | public Type[] getActualTypeArguments() { 26 | return substTypeArgs; 27 | } 28 | 29 | public Type getRawType() { 30 | return rawType; 31 | } 32 | 33 | public Type getOwnerType() { 34 | return ownerType; 35 | } 36 | 37 | @Override 38 | public boolean equals(Object obj) { 39 | if (!(obj instanceof ParameterizedType)) { 40 | return false; 41 | } 42 | ParameterizedType other = (ParameterizedType) obj; 43 | return Objects.equals(getOwnerType(), other.getOwnerType()) 44 | && Objects.equals(getRawType(), other.getRawType()) 45 | && Arrays.equals(getActualTypeArguments(), other.getActualTypeArguments()); 46 | } 47 | 48 | @Override 49 | public int hashCode() { 50 | return Arrays.hashCode(getActualTypeArguments()) 51 | ^ Objects.hashCode(getOwnerType()) 52 | ^ Objects.hashCode(getRawType()); 53 | } 54 | 55 | @Override 56 | public String toString() { 57 | final StringBuilder sb = new StringBuilder(); 58 | if (ownerType != null) { 59 | sb.append(ownerType.getTypeName()); 60 | 61 | sb.append("$"); 62 | 63 | if (ownerType instanceof ParameterizedType) { 64 | // Find simple name of nested type by removing the 65 | // shared prefix with owner. 66 | sb.append( 67 | rawType.getTypeName().replace( 68 | ((ParameterizedType) ownerType).getRawType().getTypeName() + "$", 69 | "" 70 | ) 71 | ); 72 | } else if (rawType instanceof Class) { 73 | sb.append(((Class) rawType).getSimpleName()); 74 | } else { 75 | sb.append(rawType.getTypeName()); 76 | } 77 | } else { 78 | sb.append(rawType.getTypeName()); 79 | } 80 | 81 | if (substTypeArgs != null) { 82 | final StringJoiner sj = new StringJoiner(", ", "<", ">"); 83 | sj.setEmptyValue(""); 84 | for (Type t : substTypeArgs) { 85 | sj.add(t.getTypeName()); 86 | } 87 | sb.append(sj); 88 | } 89 | 90 | return sb.toString(); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/java/generics/SimpleTypeEnvironment.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection.java.generics; 6 | 7 | import java.lang.reflect.GenericArrayType; 8 | import java.lang.reflect.ParameterizedType; 9 | import java.lang.reflect.Type; 10 | import java.lang.reflect.TypeVariable; 11 | import java.lang.reflect.WildcardType; 12 | import java.util.HashMap; 13 | import java.util.Objects; 14 | 15 | /** 16 | * Binds formal type arguments (typically T, E, etc.) to actual types. 17 | * 18 | * @author Davide Marchignoli 19 | * @author Paolo Perrotta 20 | */ 21 | final class SimpleTypeEnvironment implements TypeEnvironment { 22 | 23 | private final HashMap typeMap = new HashMap<>(); 24 | 25 | private final TypeSwitch substitute = new TypeSwitch() { 26 | @Override 27 | public Type caseClass(Class classType) { 28 | return classType; 29 | } 30 | 31 | @Override 32 | public Type caseGenericArrayType(GenericArrayType genericArrayType) { 33 | Type originalComponentType = genericArrayType.getGenericComponentType(); 34 | Type boundComponentType = bind( originalComponentType ); 35 | // try to keep the original type if possible 36 | if ( originalComponentType == boundComponentType ) { 37 | return genericArrayType; 38 | } 39 | return TypeFactory.createArrayType( boundComponentType ); 40 | } 41 | 42 | @Override 43 | public Type caseParameterizedType(ParameterizedType parameterizedType) { 44 | Type[] originalArguments = parameterizedType.getActualTypeArguments(); 45 | Type[] boundArguments = substitute( originalArguments ); 46 | // try to keep the original type if possible 47 | if ( areSame( originalArguments, boundArguments ) ) { 48 | return parameterizedType; 49 | } 50 | return new ParameterizedTypeImpl( 51 | parameterizedType.getRawType(), boundArguments, parameterizedType.getOwnerType() 52 | ); 53 | } 54 | 55 | private boolean areSame(Object[] array1, Object[] array2) { 56 | if ( array1.length != array2.length ) { 57 | return false; 58 | } 59 | for ( int i = 0; i < array1.length ; i++ ) { 60 | if ( array1[i] != array2[i] ) { 61 | return false; 62 | } 63 | } 64 | return true; 65 | } 66 | 67 | @Override 68 | public Type caseTypeVariable(TypeVariable typeVariable) { 69 | final Type type = typeMap.get( typeVariable ); 70 | if ( type == null ) { 71 | return typeVariable; 72 | } 73 | return type; 74 | } 75 | 76 | @Override 77 | public Type caseWildcardType(WildcardType wildcardType) { 78 | return wildcardType; 79 | } 80 | }; 81 | 82 | public SimpleTypeEnvironment(Type[] formalTypeArgs, Type[] actualTypeArgs) { 83 | for ( int i = 0; i < formalTypeArgs.length; i++ ) { 84 | typeMap.put( formalTypeArgs[i], actualTypeArgs[i] ); 85 | } 86 | } 87 | 88 | public Type bind(Type type) { 89 | return substitute.doSwitch( type ); 90 | } 91 | 92 | private Type[] substitute(Type[] types) { 93 | Type[] substTypes = new Type[types.length]; 94 | for ( int i = 0; i < substTypes.length ; i++ ) { 95 | substTypes[i] = bind( types[i] ); 96 | } 97 | return substTypes; 98 | } 99 | 100 | @Override 101 | public boolean equals(Object o) { 102 | if ( this == o ) { 103 | return true; 104 | } 105 | if ( o == null || SimpleTypeEnvironment.class != o.getClass() ) { 106 | return false; 107 | } 108 | SimpleTypeEnvironment that = (SimpleTypeEnvironment) o; 109 | return Objects.equals( typeMap, that.typeMap ); 110 | } 111 | 112 | @Override 113 | public int hashCode() { 114 | return Objects.hash( typeMap ); 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/java/generics/TypeEnvironment.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection.java.generics; 6 | 7 | import java.lang.reflect.Type; 8 | 9 | /** 10 | * A typing context that knows how to "resolve" the generic parameters of a 11 | * Type. 12 | *

13 | * For example: 14 | *

15 |  * {@code
16 |  *  class Shop<T> {
17 |  *    List<T> getCatalog() { ... }
18 |  *  }
19 |  * }
20 |  * 
21 | *

22 | *

23 |  * {@code
24 |  * class Bakery extends Shop { ... }
25 |  * }
26 |  * 
27 | *

28 | * Consider the type returned by method getCatalog(). There are 29 | * two possible contexts here. In the context of Shop, the type 30 | * is List. In the context of Bakery, the 31 | * type is List. Each of these contexts can be 32 | * represented by a TypeEnvironment. 33 | * 34 | * @author Davide Marchignoli 35 | * @author Paolo Perrotta 36 | */ 37 | public interface TypeEnvironment { 38 | 39 | /** 40 | * Binds as many generic components of the given type as possible in this 41 | * context. 42 | *

43 | * Warning: if the returned Type is a Class, 44 | * then it's guaranteed to be a regular Java Class. In all 45 | * other cases, this method might return a custom implementation of some 46 | * interface that extends Type. Be sure not to mix these 47 | * objects with Java's implementations of Type to avoid 48 | * potential identity problems. 49 | *

50 | * This class does not support bindings involving inner classes or 51 | * upper/lower bounds. 52 | * 53 | * @return a type where the generic arguments have been replaced by raw 54 | * classes whenever this is possible. 55 | */ 56 | public Type bind(Type type); 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/java/generics/TypeEnvironmentFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection.java.generics; 6 | 7 | import java.lang.reflect.ParameterizedType; 8 | import java.lang.reflect.Type; 9 | import java.lang.reflect.TypeVariable; 10 | 11 | /** 12 | * Returns the type context for a given Class or ParameterizedType. 13 | *

14 | * Does not support bindings involving inner classes, nor upper/lower bounds. 15 | * 16 | * @author Davide Marchignoli 17 | * @author Paolo Perrotta 18 | */ 19 | public final class TypeEnvironmentFactory { 20 | 21 | private TypeEnvironmentFactory() { 22 | //no need to construct 23 | } 24 | 25 | /** 26 | * @return Returns a type environment suitable for resolving types occurring 27 | * in subclasses of the context class. 28 | */ 29 | public static TypeEnvironment getEnvironment(Class context) { 30 | if ( context == null ) { 31 | return IdentityTypeEnvironment.INSTANCE; 32 | } 33 | return createEnvironment( context ); 34 | } 35 | 36 | public static TypeEnvironment getEnvironment(Type context) { 37 | if ( context == null ) { 38 | return IdentityTypeEnvironment.INSTANCE; 39 | } 40 | return createEnvironment( context ); 41 | } 42 | 43 | public static TypeEnvironment getEnvironment(Type t, TypeEnvironment context) { 44 | return CompoundTypeEnvironment.create( getEnvironment( t ), context ); 45 | } 46 | 47 | public static TypeEnvironment toApproximatingEnvironment(TypeEnvironment context) { 48 | return CompoundTypeEnvironment.create( new ApproximatingTypeEnvironment(), context ); 49 | } 50 | 51 | private static TypeEnvironment createEnvironment(Type context) { 52 | return new TypeSwitch() { 53 | @Override 54 | public TypeEnvironment caseClass(Class classType) { 55 | return CompoundTypeEnvironment.create( 56 | createSuperTypeEnvironment( classType ), 57 | getEnvironment( classType.getSuperclass() ) 58 | ); 59 | } 60 | 61 | @Override 62 | public TypeEnvironment caseParameterizedType(ParameterizedType parameterizedType) { 63 | return createEnvironment( parameterizedType ); 64 | } 65 | 66 | @Override 67 | public TypeEnvironment defaultCase(Type t) { 68 | throw new IllegalArgumentException( "Invalid type for generating environment: " + t ); 69 | } 70 | }.doSwitch( context ); 71 | } 72 | 73 | private static TypeEnvironment createSuperTypeEnvironment(Class clazz) { 74 | Class superclass = clazz.getSuperclass(); 75 | if ( superclass == null ) { 76 | return IdentityTypeEnvironment.INSTANCE; 77 | } 78 | 79 | Type genericSuperclass = clazz.getGenericSuperclass(); 80 | 81 | if ( genericSuperclass instanceof Class ) { 82 | return IdentityTypeEnvironment.INSTANCE; 83 | } 84 | 85 | if ( genericSuperclass instanceof ParameterizedType ) { 86 | Type[] formalArgs = superclass.getTypeParameters(); 87 | Type[] actualArgs = ( (ParameterizedType) genericSuperclass ).getActualTypeArguments(); 88 | return new SimpleTypeEnvironment( formalArgs, actualArgs ); 89 | } 90 | 91 | throw new AssertionError( "Should be unreachable" ); 92 | } 93 | 94 | private static TypeEnvironment createEnvironment(ParameterizedType t) { 95 | Type[] tactuals = t.getActualTypeArguments(); 96 | Type rawType = t.getRawType(); 97 | if ( rawType instanceof Class ) { 98 | TypeVariable[] tparms = ( (Class) rawType ).getTypeParameters(); 99 | return new SimpleTypeEnvironment( tparms, tactuals ); 100 | } 101 | return IdentityTypeEnvironment.INSTANCE; 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/java/generics/TypeFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection.java.generics; 6 | 7 | import java.lang.reflect.Array; 8 | import java.lang.reflect.GenericArrayType; 9 | import java.lang.reflect.ParameterizedType; 10 | import java.lang.reflect.Type; 11 | 12 | /** 13 | * This class instances our own ParameterizedTypes and GenericArrayTypes. 14 | * These are not supposed to be mixed with Java's implementations - beware of 15 | * equality/identity problems. 16 | * 17 | * @author Paolo Perrotta 18 | */ 19 | class TypeFactory { 20 | 21 | static ParameterizedType createParameterizedType(Type rawType, Type[] substTypeArgs, Type ownerType) { 22 | return new ParameterizedTypeImpl( rawType, substTypeArgs, ownerType ); 23 | } 24 | 25 | static Type createArrayType(Type componentType) { 26 | if ( componentType instanceof Class ) { 27 | return Array.newInstance( (Class) componentType, 0 ).getClass(); 28 | } 29 | return createGenericArrayType( componentType ); 30 | } 31 | 32 | private static GenericArrayType createGenericArrayType(Type componentType) { 33 | return new GenericArrayTypeImpl( componentType ); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/java/generics/TypeSwitch.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection.java.generics; 6 | 7 | import java.lang.reflect.GenericArrayType; 8 | import java.lang.reflect.ParameterizedType; 9 | import java.lang.reflect.Type; 10 | import java.lang.reflect.TypeVariable; 11 | import java.lang.reflect.WildcardType; 12 | 13 | /** 14 | * A visitor for the java.lang.reflect.Type hierarchy. 15 | * 16 | * @author Davide Marchignoli 17 | * @author Paolo Perrotta 18 | */ 19 | public class TypeSwitch { 20 | 21 | public final T doSwitch(Type type) { 22 | if ( type instanceof Class ) { 23 | return caseClass( (Class) type ); 24 | } 25 | if ( type instanceof GenericArrayType ) { 26 | return caseGenericArrayType( (GenericArrayType) type ); 27 | } 28 | if ( type instanceof ParameterizedType ) { 29 | return caseParameterizedType( (ParameterizedType) type ); 30 | } 31 | if ( type instanceof TypeVariable ) { 32 | return caseTypeVariable( (TypeVariable) type ); 33 | } 34 | if ( type instanceof WildcardType ) { 35 | return caseWildcardType( (WildcardType) type ); 36 | } 37 | return defaultCase( type ); 38 | } 39 | 40 | public T caseWildcardType(WildcardType wildcardType) { 41 | return defaultCase( wildcardType ); 42 | } 43 | 44 | public T caseTypeVariable(TypeVariable typeVariable) { 45 | return defaultCase( typeVariable ); 46 | } 47 | 48 | public T caseClass(Class classType) { 49 | return defaultCase( classType ); 50 | } 51 | 52 | public T caseGenericArrayType(GenericArrayType genericArrayType) { 53 | return defaultCase( genericArrayType ); 54 | } 55 | 56 | public T caseParameterizedType(ParameterizedType parameterizedType) { 57 | return defaultCase( parameterizedType ); 58 | } 59 | 60 | public T defaultCase(Type t) { 61 | return null; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/org/hibernate/annotations/common/reflection/java/generics/TypeUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.reflection.java.generics; 6 | 7 | import java.lang.reflect.GenericArrayType; 8 | import java.lang.reflect.ParameterizedType; 9 | import java.lang.reflect.Type; 10 | import java.lang.reflect.TypeVariable; 11 | import java.lang.reflect.WildcardType; 12 | import java.util.Collection; 13 | 14 | /** 15 | * @author Paolo Perrotta 16 | */ 17 | public class TypeUtils { 18 | 19 | public static boolean isResolved(Type t) { 20 | return new TypeSwitch() { 21 | @Override 22 | public Boolean caseClass(Class classType) { 23 | return true; 24 | } 25 | 26 | @Override 27 | public Boolean caseGenericArrayType(GenericArrayType genericArrayType) { 28 | return isResolved( genericArrayType.getGenericComponentType() ); 29 | } 30 | 31 | @Override 32 | public Boolean caseParameterizedType(ParameterizedType parameterizedType) { 33 | Type[] typeArgs = parameterizedType.getActualTypeArguments(); 34 | for ( Type arg : typeArgs ) { 35 | if ( !isResolved( arg ) ) { 36 | return false; 37 | } 38 | } 39 | return isResolved( parameterizedType.getRawType() ); 40 | } 41 | 42 | @Override 43 | public Boolean caseTypeVariable(TypeVariable typeVariable) { 44 | return false; 45 | } 46 | 47 | @Override 48 | public Boolean caseWildcardType(WildcardType wildcardType) { 49 | return areResolved( wildcardType.getUpperBounds() ) && areResolved( wildcardType.getLowerBounds() ); 50 | } 51 | }.doSwitch( t ); 52 | } 53 | 54 | private static Boolean areResolved(Type[] types) { 55 | for ( Type t : types ) { 56 | if ( !isResolved( t ) ) { 57 | return false; 58 | } 59 | } 60 | return true; 61 | } 62 | 63 | public static Class getCollectionClass(Type type) { 64 | return new TypeSwitch>() { 65 | @Override 66 | @SuppressWarnings("unchecked") 67 | public Class caseClass(Class clazz) { 68 | return isCollectionClass( clazz ) ? (Class) clazz : null; 69 | } 70 | 71 | @Override 72 | public Class caseParameterizedType(ParameterizedType parameterizedType) { 73 | return getCollectionClass( parameterizedType.getRawType() ); 74 | } 75 | 76 | @Override 77 | public Class caseWildcardType(WildcardType wildcardType) { 78 | Type[] upperBounds = wildcardType.getUpperBounds(); 79 | if ( upperBounds.length == 0 ) { 80 | return null; 81 | } 82 | return getCollectionClass( upperBounds[0] ); 83 | } 84 | 85 | @Override 86 | public Class defaultCase(Type t) { 87 | return null; 88 | } 89 | }.doSwitch( type ); 90 | } 91 | 92 | private static boolean isCollectionClass(Class clazz) { 93 | return Collection.class.isAssignableFrom( clazz) 94 | || java.util.Map.class.isAssignableFrom( clazz); 95 | } 96 | 97 | public static boolean isSimple(Type type) { 98 | return new TypeSwitch() { 99 | @Override 100 | public Boolean caseClass(Class clazz) { 101 | return !clazz.isArray() && !isCollectionClass( clazz ); // probably not fully accurate 102 | } 103 | 104 | @Override 105 | public Boolean caseParameterizedType(ParameterizedType parameterizedType) { 106 | return isSimple( parameterizedType.getRawType() ); 107 | } 108 | 109 | @Override 110 | public Boolean caseWildcardType(WildcardType wildcardType) { 111 | return areSimple( wildcardType.getUpperBounds() ) && areSimple( wildcardType.getLowerBounds() ); 112 | } 113 | 114 | @Override 115 | public Boolean defaultCase(Type t) { 116 | return false; 117 | } 118 | }.doSwitch( type ); 119 | } 120 | 121 | private static Boolean areSimple(Type[] types) { 122 | for ( Type t : types ) { 123 | if ( !isSimple( t ) ) { 124 | return false; 125 | } 126 | } 127 | return true; 128 | } 129 | 130 | @SuppressWarnings("EqualsBetweenInconvertibleTypes") 131 | public static boolean isVoid(Type type) { 132 | return void.class.equals( type ); 133 | } 134 | 135 | public static boolean isArray(Type t) { 136 | return new TypeSwitch() { 137 | @Override 138 | public Boolean caseClass(Class clazz) { 139 | return clazz.isArray(); 140 | } 141 | 142 | @Override 143 | public Boolean caseGenericArrayType(GenericArrayType genericArrayType) { 144 | return isSimple( genericArrayType.getGenericComponentType() ); 145 | } 146 | 147 | @Override 148 | public Boolean defaultCase(Type type) { 149 | return false; 150 | } 151 | }.doSwitch( t ); 152 | } 153 | 154 | public static boolean isCollection(Type t) { 155 | return getCollectionClass( t ) != null; 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /src/main/javadoc/jdstyle.css: -------------------------------------------------------------------------------- 1 | /* Javadoc style sheet */ 2 | 3 | /* Define colors, fonts and other style attributes here to override the defaults */ 4 | 5 | /* Page background color */ 6 | body { font-family: Arial; 7 | background-color: white; 8 | font-size: 10pt; 9 | } 10 | td { font-family: Arial; 11 | font-size: 10pt; 12 | } 13 | /* Table colors */ 14 | .TableHeadingColor { background: #F4F4F4 } 15 | .TableSubHeadingColor { background: #F4F4F4 } 16 | .TableRowColor { background: #FFFFFF } 17 | 18 | /* Font used in left-hand frame lists */ 19 | .FrameTitleFont { font-size: normal; font-family: Arial } 20 | .FrameHeadingFont { font-size: normal; font-family: Arial } 21 | .FrameItemFont { font-size: normal; font-family: Arial } 22 | 23 | /* Example of smaller, sans-serif font in frames */ 24 | /* .FrameItemFont { font-size: 10pt; font-family: Helvetica, Arial, sans-serif } */ 25 | 26 | /* Navigation bar fonts and colors */ 27 | .NavBarCell1 { background-color:#F4F4F4;} 28 | .NavBarCell1Rev { background-color:silver;} 29 | 30 | .NavBarFont1 { font-family: Arial, Helvetica, sans-serif; color:#000000;} 31 | .NavBarFont1Rev { font-family: Arial, Helvetica, sans-serif; color:#FFFFFF;} 32 | 33 | .NavBarCell2 { font-family: Arial, Helvetica, sans-serif; background-color:#FFFFFF;} 34 | .NavBarCell3 { font-family: Arial, Helvetica, sans-serif; background-color:#FFFFFF;} 35 | 36 | A { 37 | color: #003399; 38 | } 39 | 40 | A:active { 41 | color: #003399; 42 | } 43 | 44 | A:visited { 45 | color: #888888; 46 | } 47 | 48 | P, OL, UL, LI, DL, DT, DD, BLOCKQUOTE { 49 | color: #000000; 50 | } 51 | 52 | TD, TH, SPAN { 53 | color: #000000; 54 | } 55 | 56 | BLOCKQUOTE { 57 | margin-right: 0px; 58 | } 59 | 60 | 61 | /*H1, H2, H3, H4, H5, H6 { 62 | color: #000000; 63 | font-weight:500; 64 | margin-top:10px; 65 | padding-top:15px; 66 | } 67 | 68 | H1 { font-size: 150%; } 69 | H2 { font-size: 140%; } 70 | H3 { font-size: 110%; font-weight: bold; } 71 | H4 { font-size: 110%; font-weight: bold;} 72 | H5 { font-size: 100%; font-style: italic; } 73 | H6 { font-size: 100%; font-style: italic; }*/ 74 | 75 | TT { 76 | font-size: 90%; 77 | font-family: "Courier New", Courier, monospace; 78 | color: #000000; 79 | } 80 | 81 | PRE { 82 | font-size: 90%; 83 | padding: 5px; 84 | border-style: solid; 85 | border-width: 1px; 86 | border-color: #CCCCCC; 87 | background-color: #F4F4F4; 88 | } 89 | 90 | UL, OL, LI { 91 | list-style: disc; 92 | } 93 | 94 | HR { 95 | width: 100%; 96 | height: 1px; 97 | background-color: #CCCCCC; 98 | border-width: 0px; 99 | padding: 0px; 100 | color: #CCCCCC; 101 | } 102 | 103 | .variablelist { 104 | padding-top: 10; 105 | padding-bottom:10; 106 | margin:0; 107 | } 108 | 109 | .itemizedlist, UL { 110 | padding-top: 0; 111 | padding-bottom:0; 112 | margin:0; 113 | } 114 | 115 | .term { 116 | font-weight:bold; 117 | } 118 | -------------------------------------------------------------------------------- /src/main/javadoc/package.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/test/java/org/hibernate/annotations/common/test/annotationfactory/AnnotationFactoryTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.test.annotationfactory; 6 | 7 | import junit.framework.TestCase; 8 | import org.hibernate.annotations.common.annotationfactory.AnnotationDescriptor; 9 | import org.hibernate.annotations.common.annotationfactory.AnnotationFactory; 10 | 11 | /** 12 | * @author Paolo Perrotta 13 | * @author Davide Marchignoli 14 | */ 15 | public class AnnotationFactoryTest extends TestCase { 16 | 17 | public void testCreatesProxyInstancesOfAnnotations() { 18 | // Step 1: define the annotation descriptor. 19 | // 20 | // What you can/must do: 21 | // - You can assign values with the wrong type to the annotation 22 | // elements. The code won't check that the values are the same 23 | // types as required by the Annotation interface. You will 24 | // end up receiving an exception when you access the value, though. 25 | // - You must assign a value in the descriptor to all the elements 26 | // defined in the Annotation interface that do not have a default 27 | // value. 28 | // - You can ignore in the descriptor those Annotation elements that 29 | // have default values, or you can set them to override their 30 | // default values. 31 | AnnotationDescriptor descriptor = new AnnotationDescriptor( TestAnnotation.class ); 32 | descriptor.setValue( "booleanElement", false ); 33 | descriptor.setValue( "stringElement", "abc" ); 34 | descriptor.setValue( "someOtherElement", "xyz" ); 35 | 36 | // Step 2: create the annotation from its descriptor. 37 | TestAnnotation ann = AnnotationFactory.create( descriptor ); 38 | 39 | assertFalse( ann.booleanElement() ); 40 | assertEquals( "abc", ann.stringElement() ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/org/hibernate/annotations/common/test/annotationfactory/AnnotationProxyTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.test.annotationfactory; 6 | 7 | import java.lang.reflect.Method; 8 | import junit.framework.TestCase; 9 | import org.hibernate.annotations.common.annotationfactory.AnnotationDescriptor; 10 | import org.hibernate.annotations.common.annotationfactory.AnnotationProxy; 11 | 12 | /** 13 | * @author Paolo Perrotta 14 | * @author Davide Marchignoli 15 | */ 16 | public class AnnotationProxyTest extends TestCase { 17 | 18 | private AnnotationProxy ann; 19 | private AnnotationDescriptor descriptor; 20 | 21 | public void setUp() { 22 | descriptor = new AnnotationDescriptor( TestAnnotation.class ); 23 | descriptor.setValue( "stringElement", "x" ); 24 | descriptor.setValue( "booleanElement", false ); 25 | descriptor.setValue( "someOtherElement", "y" ); 26 | ann = new AnnotationProxy( descriptor ); 27 | } 28 | 29 | public void testConstructionFailsIfYouDoNotAssignValuesToAllTheElementsWithoutADefault() { 30 | try { 31 | AnnotationDescriptor desc = new AnnotationDescriptor( TestAnnotation.class ); 32 | desc.setValue( "stringElement", "x" ); 33 | desc.setValue( "booleanElement", false ); 34 | new AnnotationProxy( desc ); 35 | fail(); 36 | } 37 | catch (Exception e) { 38 | assertEquals( "No value provided for someOtherElement", e.getMessage() ); 39 | } 40 | } 41 | 42 | public void testConstructionFailsIfYouDefineElementsThatAreNotInTheAnnotationInterface() { 43 | try { 44 | AnnotationDescriptor desc = new AnnotationDescriptor( Deprecated.class ); 45 | desc.setValue( "wrongElement", "xxx" ); 46 | new AnnotationProxy( desc ); 47 | fail(); 48 | } 49 | catch (Exception e) { 50 | assertTrue( e.getMessage().contains( "unknown elements" ) ); 51 | } 52 | } 53 | 54 | public void testSupportsGenericCallsToAllElements() throws Throwable { 55 | assertEquals( "x", invoke( ann, "stringElement" ) ); 56 | assertFalse( (Boolean) invoke( ann, "booleanElement" ) ); 57 | } 58 | 59 | public void testPretendsThatItHasTheGivenType() { 60 | assertSame( TestAnnotation.class, ann.annotationType() ); 61 | } 62 | 63 | public void testItsToStringConformsToTheJavaAnnotationDocumentation() throws Throwable { 64 | String expectedString = "@org.hibernate.annotations.common.test.annotationfactory.TestAnnotation(booleanElement=false, elementWithDefault=abc, someOtherElement=y, stringElement=x)"; 65 | assertEquals( expectedString, invoke( ann, "toString" ) ); 66 | } 67 | 68 | public void testSupportsGenericCallsToMethods() throws Throwable { 69 | assertEquals( ann.annotationType(), invoke( ann, "annotationType" ) ); 70 | assertEquals( ann.toString(), invoke( ann, "toString" ) ); 71 | } 72 | 73 | public void testThrowsARuntimeExceptionIfYouUseAnElementWhichIsNotInTheAnnotationInterface() { 74 | AnnotationDescriptor elements = new AnnotationDescriptor( TestAnnotation.class ); 75 | elements.setValue( "anOddElement", "x" ); 76 | try { 77 | new AnnotationProxy( elements ); 78 | fail(); 79 | } 80 | catch (RuntimeException e) { 81 | } 82 | } 83 | 84 | public void testUsesTheDefaultValueForUndefinedElementsWhenAvailable() throws Throwable { 85 | assertEquals( "abc", invoke( ann, "elementWithDefault" ) ); 86 | } 87 | 88 | public void testThrowsANoSuchMethodExceptionWhenAccessingAnUndefinedMethod() throws Throwable { 89 | try { 90 | invoke( ann, "anElementThatDoesNotExist" ); 91 | fail(); 92 | } 93 | catch (NoSuchMethodException e) { 94 | } 95 | try { 96 | invoke( ann, "anOddElement", "arg1", "arg2" ); 97 | fail(); 98 | } 99 | catch (NoSuchMethodException e) { 100 | } 101 | } 102 | 103 | private Object invoke(AnnotationProxy proxy, String methodName, Object... args) throws Throwable { 104 | Class[] parameterTypes = new Class[args.length]; 105 | for ( int i = 0; i < args.length ; i++ ) { 106 | parameterTypes[i] = args[i].getClass(); 107 | } 108 | Method method = TestAnnotation.class.getMethod( methodName, parameterTypes ); 109 | return proxy.invoke( proxy, method, parameterTypes ); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/test/java/org/hibernate/annotations/common/test/annotationfactory/TestAnnotation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.test.annotationfactory; 6 | 7 | /** 8 | * @author Paolo Perrotta 9 | * @author Davide Marchignoli 10 | */ 11 | @interface TestAnnotation { 12 | String stringElement(); 13 | 14 | String elementWithDefault() default "abc"; 15 | 16 | boolean booleanElement(); 17 | 18 | String someOtherElement(); 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/org/hibernate/annotations/common/test/reflection/java/Foo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.test.reflection.java; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * @author Paolo Perrotta 11 | */ 12 | @TestAnnotation(name = "xyz") 13 | public class Foo extends FooFather { 14 | 15 | public static Integer staticField; 16 | 17 | Integer fieldProperty; 18 | 19 | public List getCollectionProperty() { 20 | return null; 21 | } 22 | 23 | @TestAnnotation(name = "xyz") 24 | public Integer getMethodProperty() { 25 | return null; 26 | } 27 | 28 | public int getPrimitiveProperty() { 29 | return 0; 30 | } 31 | 32 | public static Integer getStaticThing() { 33 | return null; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/org/hibernate/annotations/common/test/reflection/java/FooFather.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.test.reflection.java; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * @author Paolo Perrotta 11 | */ 12 | public abstract class FooFather { 13 | 14 | public Integer fatherField; 15 | 16 | public Boolean isFatherMethod() { 17 | return null; 18 | } 19 | 20 | public T getParameterizedProperty() { 21 | return null; 22 | } 23 | 24 | public List getParameterizedCollectionProperty() { 25 | return null; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/org/hibernate/annotations/common/test/reflection/java/JavaReflectionManagerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.test.reflection.java; 6 | 7 | import junit.framework.TestCase; 8 | import org.hibernate.annotations.common.reflection.ReflectionManager; 9 | import org.hibernate.annotations.common.reflection.XClass; 10 | import org.hibernate.annotations.common.reflection.java.JavaReflectionManager; 11 | 12 | /** 13 | * @author Paolo Perrotta 14 | */ 15 | public class JavaReflectionManagerTest extends TestCase { 16 | 17 | private ReflectionManager rm = new JavaReflectionManager(); 18 | 19 | public void testReturnsAnXClassThatWrapsTheGivenClass() { 20 | XClass xc = rm.toXClass( Integer.class ); 21 | assertEquals( "java.lang.Integer", xc.getName() ); 22 | } 23 | 24 | public void testReturnsSameXClassForSameClass() { 25 | XClass xc1 = rm.toXClass( void.class ); 26 | XClass xc2 = rm.toXClass( void.class ); 27 | assertSame( xc2, xc1 ); 28 | } 29 | 30 | public void testReturnsNullForANullClass() { 31 | assertNull( rm.toXClass( null ) ); 32 | } 33 | 34 | public void testComparesXClassesWithClasses() { 35 | XClass xc = rm.toXClass( Integer.class ); 36 | assertTrue( rm.equals( xc, Integer.class ) ); 37 | } 38 | 39 | public void testSupportsNullsInComparisons() { 40 | XClass xc = rm.toXClass( Integer.class ); 41 | assertFalse( rm.equals( null, Number.class ) ); 42 | assertFalse( rm.equals( xc, null ) ); 43 | assertTrue( rm.equals( null, null ) ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/test/java/org/hibernate/annotations/common/test/reflection/java/JavaXClassTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.test.reflection.java; 6 | 7 | import java.io.Serializable; 8 | import java.lang.reflect.ParameterizedType; 9 | import java.lang.reflect.Type; 10 | import java.util.List; 11 | import org.hibernate.annotations.common.reflection.ReflectionManager; 12 | import org.hibernate.annotations.common.reflection.XAnnotatedElement; 13 | import org.hibernate.annotations.common.reflection.XClass; 14 | import org.hibernate.annotations.common.reflection.XProperty; 15 | import org.hibernate.annotations.common.reflection.java.JavaReflectionManager; 16 | import org.hibernate.annotations.common.test.reflection.java.generics.Dad; 17 | import org.hibernate.annotations.common.test.reflection.java.generics.Grandpa; 18 | import org.hibernate.annotations.common.test.reflection.java.generics.Language; 19 | import org.hibernate.annotations.common.test.reflection.java.generics.Son; 20 | 21 | /** 22 | * @author Paolo Perrotta 23 | */ 24 | public class JavaXClassTest extends XAnnotatedElementTestCase { 25 | ReflectionManager factory = new JavaReflectionManager(); 26 | 27 | XClass fatherAsSeenFromSon = factory.toXClass( Son.class ).getSuperclass(); 28 | XClass grandpa = factory.toXClass( Grandpa.class ); 29 | 30 | public void testHasAPointOfViewClass() { 31 | // Since Dad is an Entity, getting it through Son.getSuperclass() gives 32 | // us a view of properties from Dad with Son as a point of view. 33 | XClass sameView = factory.toXClass( Son.class ).getSuperclass(); 34 | XClass differentView = factory.toXClass( Dad.class ); 35 | assertSame( "Should be the same instance: same owner", sameView, fatherAsSeenFromSon ); 36 | assertNotSame( "Should be a different instance: different owner", differentView, fatherAsSeenFromSon ); 37 | assertEquals( ".equals() should show equality", sameView, differentView ); 38 | } 39 | 40 | public void testHasAName() { 41 | assertSame( "org.hibernate.annotations.common.test.reflection.java.generics.Dad", fatherAsSeenFromSon.getName() ); 42 | } 43 | 44 | public void testHasASuperclass() { 45 | assertEquals( grandpa, fatherAsSeenFromSon.getSuperclass() ); 46 | } 47 | 48 | public void testSuperSuperClass() { 49 | assertEquals( factory.toXClass( Object.class ), grandpa.getSuperclass() ); 50 | assertEquals( null, grandpa.getSuperclass().getSuperclass() ); 51 | } 52 | 53 | public void testHasInterfaces() { 54 | XClass[] interfaces = fatherAsSeenFromSon.getSuperclass().getInterfaces(); 55 | assertEquals( 2, interfaces.length ); 56 | assertTrue( factory.equals( interfaces[0], Serializable.class ) ); 57 | assertTrue( factory.equals( interfaces[1], Language.class ) ); 58 | } 59 | 60 | public void testCanBeAssignableFromAnotherXClass() { 61 | assertFalse( fatherAsSeenFromSon.isAssignableFrom( grandpa ) ); 62 | assertTrue( grandpa.isAssignableFrom( fatherAsSeenFromSon ) ); 63 | } 64 | 65 | public void testExtractsPublicFieldsAsProperties() { 66 | List fieldProperties = fatherAsSeenFromSon.getDeclaredProperties( "field" ); 67 | assertEquals( 1, fieldProperties.size() ); 68 | } 69 | 70 | public void testExtractsPublicMethodsAsProperties() { 71 | List methodProperties = fatherAsSeenFromSon.getDeclaredProperties( "property" ); 72 | assertEquals( 9, methodProperties.size() ); 73 | } 74 | 75 | public void testCanBeAbstract() { 76 | assertFalse( fatherAsSeenFromSon.isAbstract() ); 77 | assertTrue( factory.toXClass( Grandpa.class ).isAbstract() ); 78 | } 79 | 80 | public void testCanBeAPrimitive() { 81 | assertFalse( fatherAsSeenFromSon.isPrimitive() ); 82 | assertTrue( factory.toXClass( int.class ).isPrimitive() ); 83 | } 84 | 85 | public void testCanBeAnEnum() { 86 | assertFalse( fatherAsSeenFromSon.isEnum() ); 87 | assertTrue( factory.toXClass( Sex.class ).isEnum() ); 88 | } 89 | 90 | public void testParameterizedType() { 91 | Type type = factory.toType( 92 | fatherAsSeenFromSon.getDeclaredProperties( "property" ) 93 | .stream() 94 | .filter( p -> p.getName().equals( "genericCollectionProperty" ) ) 95 | .findFirst() 96 | .get() 97 | .getType() 98 | ); 99 | assertTrue( type instanceof ParameterizedType ); 100 | assertEquals( String.class, ((ParameterizedType) type).getActualTypeArguments()[0] ); 101 | } 102 | 103 | @Override 104 | protected XAnnotatedElement getConcreteInstance() { 105 | return factory.toXClass( Dad.class ); 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /src/test/java/org/hibernate/annotations/common/test/reflection/java/JavaXPropertyTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.test.reflection.java; 6 | 7 | import java.util.LinkedList; 8 | import java.util.List; 9 | import java.util.Map; 10 | import junit.framework.AssertionFailedError; 11 | import org.hibernate.annotations.common.reflection.Filter; 12 | import org.hibernate.annotations.common.reflection.ReflectionManager; 13 | import org.hibernate.annotations.common.reflection.XClass; 14 | import org.hibernate.annotations.common.reflection.XProperty; 15 | import org.hibernate.annotations.common.reflection.java.JavaReflectionManager; 16 | import org.hibernate.annotations.common.test.reflection.java.generics.Dad; 17 | import org.hibernate.annotations.common.test.reflection.java.generics.Son; 18 | 19 | /** 20 | * @author Paolo Perrotta 21 | */ 22 | public class JavaXPropertyTest extends XAnnotatedElementTestCase { 23 | 24 | private ReflectionManager factory = new JavaReflectionManager(); 25 | 26 | private XClass dadAsSeenFromItself = factory.toXClass( Dad.class ); 27 | 28 | private XClass dadAsSeenFromSon = factory.toXClass( Son.class ).getSuperclass(); 29 | 30 | public void testFollowsJavaBeansConventionsForPropertyNames() throws Exception { 31 | List properties = new LinkedList(); 32 | properties.add( "collectionProperty" ); 33 | properties.add( "methodProperty" ); 34 | properties.add( "primitiveProperty" ); 35 | properties.add( "primitiveArrayProperty" ); 36 | properties.add( "arrayProperty" ); 37 | properties.add( "genericCollectionProperty" ); 38 | properties.add( "nongenericCollectionProperty" ); 39 | properties.add( "propertyStartingWithIs" ); 40 | properties.add( "language" ); 41 | List methodProperties = dadAsSeenFromSon.getDeclaredProperties( "property" ); 42 | assertEquals( properties.size(), methodProperties.size() ); 43 | for ( XProperty member : methodProperties ) { 44 | assertTrue( properties.contains( member.getName() ) ); 45 | } 46 | List fieldProperties = dadAsSeenFromSon.getDeclaredProperties( "field" ); 47 | XProperty field = fieldProperties.get( 0 ); 48 | assertEquals( "fieldProperty", field.getName() ); 49 | } 50 | 51 | public void testReturnsPropertiesWithUnresolvedParametricTypes() { 52 | assertEquals( 9, dadAsSeenFromItself.getDeclaredProperties( "property" ).size() ); 53 | } 54 | 55 | public void testKnowsWhetherItsTypeIsFullyResolved() { 56 | XProperty notFullyResolvedProperty = getPropertyNamed_from( 57 | "collectionProperty", dadAsSeenFromItself 58 | .getDeclaredProperties( "property" ) 59 | ); 60 | assertFalse( notFullyResolvedProperty.isTypeResolved() ); 61 | XProperty fullyResolvedProperty = getPropertyNamed_from( 62 | "collectionProperty", dadAsSeenFromSon 63 | .getDeclaredProperties( "property" ) 64 | ); 65 | assertTrue( fullyResolvedProperty.isTypeResolved() ); 66 | } 67 | 68 | public void testCanBeFiltered() { 69 | assertEquals( 70 | 10, dadAsSeenFromSon.getDeclaredProperties( 71 | "property", new Filter() { 72 | 73 | public boolean returnStatic() { 74 | return true; 75 | } 76 | 77 | public boolean returnTransient() { 78 | return false; 79 | } 80 | } 81 | ).size() 82 | ); 83 | } 84 | 85 | public void testCanBeASimpleType() { 86 | List declaredProperties = dadAsSeenFromSon.getDeclaredProperties( "field" ); 87 | XProperty p = getPropertyNamed_from( "fieldProperty", declaredProperties ); 88 | assertTrue( factory.equals( p.getType(), String.class ) ); 89 | assertTrue( factory.equals( p.getElementClass(), String.class ) ); 90 | assertTrue( factory.equals( p.getClassOrElementClass(), String.class ) ); 91 | assertNull( p.getCollectionClass() ); 92 | assertFalse( p.isArray() ); 93 | assertFalse( p.isCollection() ); 94 | } 95 | 96 | public void testResolveInterfaceType() { 97 | List declaredProperties = dadAsSeenFromSon.getDeclaredProperties( "property" ); 98 | XProperty p = getPropertyNamed_from( "language", declaredProperties ); 99 | assertTrue( factory.equals( p.getType(), String.class ) ); 100 | assertTrue( factory.equals( p.getElementClass(), String.class ) ); 101 | assertTrue( factory.equals( p.getClassOrElementClass(), String.class ) ); 102 | assertNull( p.getCollectionClass() ); 103 | assertNull( p.getMapKey() ); 104 | assertFalse( p.isArray() ); 105 | assertFalse( p.isCollection() ); 106 | } 107 | 108 | public void testCanBeAnArray() { 109 | List declaredProperties = dadAsSeenFromSon.getDeclaredProperties( "property" ); 110 | XProperty p = getPropertyNamed_from( "arrayProperty", declaredProperties ); 111 | assertTrue( factory.equals( p.getType(), String[].class ) ); 112 | assertTrue( factory.equals( p.getElementClass(), String.class ) ); 113 | assertTrue( factory.equals( p.getClassOrElementClass(), String.class ) ); 114 | assertNull( p.getCollectionClass() ); 115 | assertNull( p.getMapKey() ); 116 | assertTrue( p.isArray() ); 117 | assertFalse( p.isCollection() ); 118 | } 119 | 120 | public void testCanBeAnArrayOfPrimitives() { 121 | List declaredProperties = dadAsSeenFromSon.getDeclaredProperties( "property" ); 122 | XProperty p = getPropertyNamed_from( "primitiveArrayProperty", declaredProperties ); 123 | assertTrue( factory.equals( p.getType(), int[].class ) ); 124 | assertTrue( factory.equals( p.getElementClass(), int.class ) ); 125 | assertTrue( factory.equals( p.getClassOrElementClass(), int.class ) ); 126 | assertNull( p.getCollectionClass() ); 127 | assertNull( p.getMapKey() ); 128 | assertTrue( p.isArray() ); 129 | assertFalse( p.isCollection() ); 130 | } 131 | 132 | public void testCanBeACollection() { 133 | List declaredProperties = dadAsSeenFromSon.getDeclaredProperties( "property" ); 134 | XProperty p = getPropertyNamed_from( "collectionProperty", declaredProperties ); 135 | assertTrue( factory.equals( p.getType(), Map.class ) ); 136 | assertTrue( factory.equals( p.getElementClass(), String.class ) ); 137 | assertTrue( factory.equals( p.getClassOrElementClass(), Map.class ) ); 138 | assertTrue( factory.equals( p.getMapKey(), Double.class ) ); 139 | assertEquals( Map.class, p.getCollectionClass() ); 140 | assertFalse( p.isArray() ); 141 | assertTrue( p.isCollection() ); 142 | } 143 | 144 | private XProperty getPropertyNamed_from(String name, List properties) { 145 | for ( XProperty p : properties ) { 146 | if ( p.getName().equals( name ) ) { 147 | return p; 148 | } 149 | } 150 | throw new AssertionFailedError( "No property '" + name + "' found" ); 151 | } 152 | 153 | public void testSupportsMethodsStartingWithIs() throws Exception { 154 | assertEquals( "methodProperty", getConcreteInstance().getName() ); 155 | } 156 | 157 | @Override 158 | protected XProperty getConcreteInstance() { 159 | XClass xClass = factory.toXClass( Dad.class ); 160 | List properties = xClass.getDeclaredProperties( "property" ); 161 | for ( XProperty p : properties ) { 162 | if ( p.getName().equals( "methodProperty" ) ) { 163 | return p; 164 | } 165 | } 166 | throw new AssertionFailedError( "Cannot find Foo.getMethodProperty()" ); 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/test/java/org/hibernate/annotations/common/test/reflection/java/Sex.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.test.reflection.java; 6 | 7 | /** 8 | * @author Emmanuel Bernard 9 | */ 10 | public enum Sex { 11 | MALE, 12 | FEMALE 13 | } 14 | -------------------------------------------------------------------------------- /src/test/java/org/hibernate/annotations/common/test/reflection/java/TestAnnotation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.test.reflection.java; 6 | 7 | import static java.lang.annotation.ElementType.*; 8 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 9 | 10 | import java.lang.annotation.Retention; 11 | import java.lang.annotation.Target; 12 | 13 | @Target({TYPE, METHOD, FIELD}) 14 | @Retention(RUNTIME) 15 | public @interface TestAnnotation { 16 | String name() default "abc"; 17 | } 18 | -------------------------------------------------------------------------------- /src/test/java/org/hibernate/annotations/common/test/reflection/java/XAnnotatedElementTestCase.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.test.reflection.java; 6 | 7 | import junit.framework.TestCase; 8 | import org.hibernate.annotations.common.reflection.XAnnotatedElement; 9 | import org.hibernate.annotations.common.test.reflection.java.generics.TestAnnotation; 10 | 11 | /** 12 | * @author Paolo Perrotta 13 | */ 14 | public abstract class XAnnotatedElementTestCase extends TestCase { 15 | 16 | public void testKnowsWhetherAnAnnotationIsPresent() { 17 | assertTrue( getConcreteInstance().isAnnotationPresent( TestAnnotation.class ) ); 18 | assertFalse( getConcreteInstance().isAnnotationPresent( Override.class ) ); 19 | } 20 | 21 | public void testReturnsSpecificAnnotations() { 22 | TestAnnotation ent = getConcreteInstance().getAnnotation( TestAnnotation.class ); 23 | assertEquals( "xyz", ent.name() ); 24 | } 25 | 26 | protected abstract XAnnotatedElement getConcreteInstance(); 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/org/hibernate/annotations/common/test/reflection/java/generics/ApproximatingTypeEnvironmentTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.test.reflection.java.generics; 6 | 7 | import java.lang.reflect.ParameterizedType; 8 | import java.lang.reflect.Type; 9 | import java.util.Collection; 10 | import java.util.Map; 11 | import junit.framework.TestCase; 12 | import org.hibernate.annotations.common.reflection.java.generics.TypeEnvironment; 13 | import org.hibernate.annotations.common.reflection.java.generics.TypeEnvironmentFactory; 14 | 15 | public class ApproximatingTypeEnvironmentTest extends TestCase { 16 | 17 | TypeEnvironment unboundContext = TypeEnvironmentFactory.getEnvironment( BigBlob.class ); 18 | TypeEnvironment approximatingUnboundContext = TypeEnvironmentFactory.toApproximatingEnvironment( unboundContext ); 19 | 20 | TypeEnvironment boundContext = TypeEnvironmentFactory.getEnvironment( SonOfBlob.class ); 21 | TypeEnvironment approximatingBoundContext = TypeEnvironmentFactory.toApproximatingEnvironment( boundContext ); 22 | 23 | public void testDoesNothingOnClasses() throws SecurityException { 24 | assertEquals( String[].class, approximatingUnboundContext.bind( String[].class ) ); 25 | } 26 | 27 | public void testDoesNothingOnWildcards() throws Exception { 28 | Type type = BigBlob.class.getMethod( "genericClass", new Class[0] ).getGenericReturnType(); 29 | Type approxType = approximatingBoundContext.bind( type ); 30 | assertEquals( "java.lang.Class", approxType.toString() ); 31 | } 32 | 33 | public void testDoesNothingOnParameterizedTypesThatAreAlreadyFullyBound() throws Exception { 34 | Type type = BigBlob.class.getMethod( "simpleGenericType", new Class[0] ).getGenericReturnType(); 35 | assertEquals( boundContext.bind( type ), approximatingBoundContext.bind( type ) ); 36 | } 37 | 38 | public void testDoesNothingOnComplexParameterizedTypesThatAreNotCollections() throws Exception { 39 | Type type = BigBlob.class.getMethod( "genericType", new Class[0] ).getGenericReturnType(); 40 | assertEquals( boundContext.bind( type ), approximatingBoundContext.bind( type ) ); 41 | } 42 | 43 | public void testDoesNothingOnGenericArraysThatAreAlreadyFullyBound() throws Exception { 44 | Type type = BigBlob.class.getMethod( "array", new Class[0] ).getGenericReturnType(); 45 | assertEquals( boundContext.bind( type ), approximatingBoundContext.bind( type ) ); 46 | } 47 | 48 | public void testApproximatesSimpleGenericTypesToTheirUpperBound() throws Exception { 49 | Type type = BigBlob.class.getMethod( "simpleGenericType", new Class[0] ).getGenericReturnType(); 50 | assertEquals( "java.util.List", approximatingBoundContext.bind( type ).toString() ); 51 | } 52 | 53 | public void testApproximatesGenericsInArraysToTheirUpperBounds() throws Exception { 54 | Type type = BigBlob.class.getMethod( "array", new Class[0] ).getGenericReturnType(); 55 | assertEquals( Collection[].class, approximatingUnboundContext.bind( type ) ); 56 | } 57 | 58 | public void testApproximatesArraysOfComplexTypesToArraysOfObjects() throws Exception { 59 | Type type = BigBlob.class.getMethod( "complexGenericArray", new Class[0] ).getGenericReturnType(); 60 | assertEquals( Object[].class, approximatingUnboundContext.bind( type ) ); 61 | } 62 | 63 | public void testApproximatesGenericsAndWildcardsInCollectionsToTheirUpperBounds() throws Exception { 64 | Type type = BigBlob.class.getMethod( "genericCollection", new Class[0] ).getGenericReturnType(); 65 | ParameterizedType approxType = (ParameterizedType) approximatingUnboundContext.bind( type ); 66 | assertEquals( Map.class, approxType.getRawType() ); 67 | assertNull( approxType.getOwnerType() ); 68 | assertEquals( 2, approxType.getActualTypeArguments().length ); 69 | assertEquals( Object.class, approxType.getActualTypeArguments()[0] ); 70 | assertEquals( Collection.class, approxType.getActualTypeArguments()[1] ); 71 | } 72 | 73 | public void testMultipleBoundWithClass() throws Exception { 74 | Type type = MultipleBoundWithClass.class.getMethod( "getGenericType", new Class[0] ).getGenericReturnType(); 75 | Type bind = approximatingUnboundContext.bind( type ); 76 | assertEquals( String.class.getName(), bind.getTypeName() ); 77 | } 78 | 79 | public void testMultipleBoundMultipleBoundWithMultipleInterfaces() throws Exception { 80 | Type type = MultipleBoundWithMultipleInterfaces.class.getMethod( "getGenericType", new Class[0] ).getGenericReturnType(); 81 | Type bind = approximatingUnboundContext.bind( type ); 82 | assertEquals( MultipleBoundWithMultipleInterfaces.Bound.class.getName(), bind.getTypeName() ); 83 | } 84 | 85 | public void testUnboundGeneric() throws Exception { 86 | Type type = UnboundGeneric.class.getMethod( "getGenericType", new Class[0] ).getGenericReturnType(); 87 | Type bind = approximatingUnboundContext.bind( type ); 88 | assertEquals( Object.class.getName(), bind.getTypeName() ); 89 | } 90 | 91 | public void testCircularGeneric() throws Exception { 92 | Type type = CircularGeneric.class.getMethod( "getGenericType", new Class[0] ).getGenericReturnType(); 93 | Type bind = approximatingUnboundContext.bind( type ); 94 | assertEquals( CircularGeneric.class.getName(), bind.getTypeName() ); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/test/java/org/hibernate/annotations/common/test/reflection/java/generics/BigBlob.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.test.reflection.java.generics; 6 | 7 | import java.util.Collection; 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | public class BigBlob { 12 | 13 | public E simpleGenericType() { 14 | return null; 15 | } 16 | 17 | public Class genericClass() { 18 | return null; 19 | } 20 | 21 | public Class genericType() { 22 | return null; 23 | } 24 | 25 | public Map genericCollection() { 26 | return null; 27 | } 28 | 29 | public E[] array() { 30 | return null; 31 | } 32 | 33 | public List[] complexGenericArray() { 34 | return null; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/org/hibernate/annotations/common/test/reflection/java/generics/CircularGeneric.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.test.reflection.java.generics; 6 | 7 | public class CircularGeneric> { 8 | T genericType; 9 | 10 | public T getGenericType(){ 11 | return genericType; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/test/java/org/hibernate/annotations/common/test/reflection/java/generics/Dad.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.test.reflection.java.generics; 6 | 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | /** 11 | * @author Davide Marchignoli 12 | * @author Paolo Perrotta 13 | */ 14 | @TestAnnotation(name = "xyz") 15 | public class Dad extends Grandpa, Integer> { 16 | 17 | static Integer staticField; 18 | 19 | T fieldProperty; 20 | 21 | public Map getCollectionProperty() { 22 | return null; 23 | } 24 | 25 | @TestAnnotation(name = "xyz") 26 | public Integer getMethodProperty() { 27 | return null; 28 | } 29 | 30 | public int getPrimitiveProperty() { 31 | return 0; 32 | } 33 | 34 | public boolean isPropertyStartingWithIs() { 35 | return false; 36 | } 37 | 38 | public int[] getPrimitiveArrayProperty() { 39 | return null; 40 | } 41 | 42 | public T[] getArrayProperty() { 43 | return null; 44 | } 45 | 46 | public List getGenericCollectionProperty() { 47 | return null; 48 | } 49 | 50 | public List getNongenericCollectionProperty() { 51 | return null; 52 | } 53 | 54 | public static Integer getStaticThing() { 55 | return null; 56 | } 57 | 58 | public String getLanguage() { 59 | return null; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/test/java/org/hibernate/annotations/common/test/reflection/java/generics/Grandpa.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.test.reflection.java.generics; 6 | 7 | import java.io.Serializable; 8 | 9 | /** 10 | * @author Davide Marchignoli 11 | * @author Paolo Perrotta 12 | */ 13 | public abstract class Grandpa implements Serializable, Language { 14 | 15 | Integer grandpaField; 16 | 17 | public T returnsGeneric() { 18 | return null; 19 | } 20 | 21 | // generic embedded value 22 | public Neighbour getFriend() { 23 | return null; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/org/hibernate/annotations/common/test/reflection/java/generics/Language.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.test.reflection.java.generics; 6 | 7 | /** 8 | * @author Emmanuel Bernard 9 | */ 10 | public interface Language { 11 | T getLanguage(); 12 | } 13 | -------------------------------------------------------------------------------- /src/test/java/org/hibernate/annotations/common/test/reflection/java/generics/MultipleBoundWithClass.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.test.reflection.java.generics; 6 | 7 | 8 | public class MultipleBoundWithClass { 9 | T genericType; 10 | 11 | public T getGenericType(){ 12 | return genericType; 13 | } 14 | 15 | public interface Bound{ 16 | 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/org/hibernate/annotations/common/test/reflection/java/generics/MultipleBoundWithMultipleInterfaces.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.test.reflection.java.generics; 6 | 7 | 8 | public class MultipleBoundWithMultipleInterfaces { 9 | T genericType; 10 | 11 | public T getGenericType(){ 12 | return genericType; 13 | } 14 | 15 | public interface Bound{ 16 | 17 | } 18 | 19 | public interface Bound2{ 20 | 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/org/hibernate/annotations/common/test/reflection/java/generics/Neighbour.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.test.reflection.java.generics; 6 | 7 | import java.util.Set; 8 | 9 | /** 10 | * @author Davide Marchignoli 11 | * @author Paolo Perrotta 12 | */ 13 | public class Neighbour { 14 | 15 | public Set embeddedProperty() { 16 | return null; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/org/hibernate/annotations/common/test/reflection/java/generics/Son.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.test.reflection.java.generics; 6 | 7 | /** 8 | * @author Davide Marchignoli 9 | * @author Paolo Perrotta 10 | */ 11 | public class Son extends Dad { 12 | } 13 | -------------------------------------------------------------------------------- /src/test/java/org/hibernate/annotations/common/test/reflection/java/generics/SonOfBlob.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.test.reflection.java.generics; 6 | 7 | import java.util.List; 8 | 9 | 10 | public class SonOfBlob extends BigBlob> { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/test/java/org/hibernate/annotations/common/test/reflection/java/generics/TestAnnotation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.test.reflection.java.generics; 6 | 7 | import static java.lang.annotation.ElementType.*; 8 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 9 | 10 | import java.lang.annotation.Retention; 11 | import java.lang.annotation.Target; 12 | 13 | /** 14 | * @author Davide Marchignoli 15 | * @author Paolo Perrotta 16 | */ 17 | @Target({TYPE, METHOD, FIELD}) 18 | @Retention(RUNTIME) 19 | public @interface TestAnnotation { 20 | String name() default "abc"; 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/org/hibernate/annotations/common/test/reflection/java/generics/TypeEnvironmentFactoryTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.test.reflection.java.generics; 6 | 7 | import java.lang.reflect.ParameterizedType; 8 | import java.lang.reflect.Type; 9 | import java.lang.reflect.TypeVariable; 10 | import java.util.List; 11 | import java.util.Set; 12 | import junit.framework.TestCase; 13 | import org.hibernate.annotations.common.reflection.java.generics.TypeEnvironmentFactory; 14 | 15 | /** 16 | * @author Davide Marchignoli 17 | * @author Paolo Perrotta 18 | */ 19 | public class TypeEnvironmentFactoryTest extends TestCase { 20 | 21 | public void testBindsGenericsToSuperclassEnvironment() throws SecurityException, NoSuchMethodException { 22 | Type type = Grandpa.class.getMethod( "returnsGeneric" ).getGenericReturnType(); 23 | 24 | Type asSeenFromGrandpa = TypeEnvironmentFactory.getEnvironment( Grandpa.class ).bind( type ); 25 | assertTrue( asSeenFromGrandpa instanceof TypeVariable ); 26 | assertEquals( "T", asSeenFromGrandpa.toString() ); 27 | 28 | Type asSeenFromDad = TypeEnvironmentFactory.getEnvironment( Dad.class ).bind( type ); 29 | assertTrue( asSeenFromDad instanceof ParameterizedType ); 30 | assertEquals( "java.util.List", asSeenFromDad.toString() ); 31 | 32 | ParameterizedType asSeenFromSon = (ParameterizedType) TypeEnvironmentFactory.getEnvironment( Son.class ).bind( type ); 33 | assertType_isCollectionOfClass_withElementsOfClass( asSeenFromSon, List.class, String.class ); 34 | } 35 | 36 | @SuppressWarnings("unchecked") 37 | public void testBindsGenericsToOwnerEnvironment() throws SecurityException, NoSuchMethodException { 38 | Type friendType = Dad.class.getMethod( "getFriend" ).getGenericReturnType(); 39 | ParameterizedType friendTypeAsSeenFromDad = (ParameterizedType) TypeEnvironmentFactory.getEnvironment( Dad.class ).bind( 40 | friendType 41 | ); 42 | 43 | Class friendClass = (Class) friendTypeAsSeenFromDad.getRawType(); 44 | Type returnType = friendClass.getMethod( "embeddedProperty" ).getGenericReturnType(); 45 | 46 | ParameterizedType boundType = (ParameterizedType) TypeEnvironmentFactory.getEnvironment( friendTypeAsSeenFromDad ).bind( 47 | returnType 48 | ); 49 | assertType_isCollectionOfClass_withElementsOfClass( boundType, Set.class, Integer.class ); 50 | } 51 | 52 | private void assertType_isCollectionOfClass_withElementsOfClass( 53 | ParameterizedType t, Class collectionClass, 54 | Class elementClass 55 | ) { 56 | assertEquals( collectionClass, t.getRawType() ); 57 | assertEquals( 1, t.getActualTypeArguments().length ); 58 | assertEquals( elementClass, t.getActualTypeArguments()[0] ); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/test/java/org/hibernate/annotations/common/test/reflection/java/generics/TypeUtilsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.test.reflection.java.generics; 6 | 7 | import java.lang.reflect.Type; 8 | import junit.framework.TestCase; 9 | import org.hibernate.annotations.common.reflection.java.generics.TypeEnvironment; 10 | import org.hibernate.annotations.common.reflection.java.generics.TypeEnvironmentFactory; 11 | import org.hibernate.annotations.common.reflection.java.generics.TypeUtils; 12 | 13 | public class TypeUtilsTest extends TestCase { 14 | 15 | TypeEnvironment dadContext = TypeEnvironmentFactory.getEnvironment( Dad.class ); 16 | TypeEnvironment sonContext = TypeEnvironmentFactory.getEnvironment( Son.class ); 17 | 18 | public void testAClassIsAlwaysFullyResolved() throws Exception { 19 | assertTrue( TypeUtils.isResolved( Dad.class ) ); 20 | } 21 | 22 | private Type getPropertyFromDad(String propertyName) throws NoSuchMethodException { 23 | return Dad.class.getMethod( propertyName, new Class[0] ).getGenericReturnType(); 24 | } 25 | 26 | public void testKnowsWhetherAParametricTypeIsFullyResolved() throws Exception { 27 | Type simpleType = getPropertyFromDad( "returnsGeneric" ); 28 | assertFalse( TypeUtils.isResolved( dadContext.bind( simpleType ) ) ); 29 | assertTrue( TypeUtils.isResolved( sonContext.bind( simpleType ) ) ); 30 | } 31 | 32 | public void testKnowsWhetherAnArrayTypeIsFullyResolved() throws Exception { 33 | Type arrayType = getPropertyFromDad( "getArrayProperty" ); 34 | assertFalse( TypeUtils.isResolved( dadContext.bind( arrayType ) ) ); 35 | assertTrue( TypeUtils.isResolved( sonContext.bind( arrayType ) ) ); 36 | } 37 | 38 | public void testKnowsWhetherATypeIsSimple() throws Exception { 39 | assertTrue( TypeUtils.isSimple( String.class ) ); 40 | assertFalse( TypeUtils.isSimple( new String[1].getClass() ) ); 41 | assertFalse( TypeUtils.isSimple( getPropertyFromDad( "getNongenericCollectionProperty" ) ) ); 42 | assertFalse( TypeUtils.isSimple( getPropertyFromDad( "getGenericCollectionProperty" ) ) ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/test/java/org/hibernate/annotations/common/test/reflection/java/generics/UnboundGeneric.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.test.reflection.java.generics; 6 | 7 | public class UnboundGeneric { 8 | T genericType; 9 | 10 | public T getGenericType(){ 11 | return genericType; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/test/java/org/hibernate/annotations/common/test/reflection/java/generics/deep/ANN612IssueTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.test.reflection.java.generics.deep; 6 | 7 | import java.util.List; 8 | import junit.framework.TestCase; 9 | import org.hibernate.annotations.common.reflection.XClass; 10 | import org.hibernate.annotations.common.reflection.XProperty; 11 | import org.hibernate.annotations.common.reflection.java.JavaReflectionManager; 12 | 13 | 14 | /** 15 | * @author Paolo Perrotta 16 | */ 17 | public class ANN612IssueTest extends TestCase { 18 | 19 | 20 | public static class J {} 21 | 22 | public static class C { 23 | public J thisOneAlwaysWorkedFine; 24 | public J thisOneUsedToCauseProblems; 25 | } 26 | 27 | public void testANN612IssueIsFixed() throws Exception { 28 | JavaReflectionManager factory = new JavaReflectionManager(); 29 | XClass clazz = factory.toXClass( C.class ); 30 | List properties = clazz.getDeclaredProperties( XClass.ACCESS_FIELD ); 31 | for( XProperty property : properties ) 32 | assertTrue( property.isTypeResolved() ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/org/hibernate/annotations/common/test/reflection/java/generics/deep/DeepGenericsContainment.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.test.reflection.java.generics.deep; 6 | 7 | import java.util.List; 8 | import junit.framework.TestCase; 9 | import org.hibernate.annotations.common.reflection.XClass; 10 | import org.hibernate.annotations.common.reflection.XProperty; 11 | import org.hibernate.annotations.common.reflection.java.JavaReflectionManager; 12 | 13 | 14 | /** 15 | * @author Paolo Perrotta 16 | */ 17 | public class DeepGenericsContainment extends TestCase { 18 | 19 | public static class Contained { 20 | T generic; 21 | } 22 | 23 | public static class Container { 24 | Contained contained; 25 | } 26 | 27 | public static class ContainerWithCollection { 28 | List> contained; 29 | } 30 | 31 | public void test2StepsGenerics() throws Exception { 32 | JavaReflectionManager factory = new JavaReflectionManager(); 33 | XClass container = factory.toXClass( Container.class ); 34 | XProperty contained = container.getDeclaredProperties( XClass.ACCESS_FIELD ).get( 0 ); 35 | assertTrue( contained.isTypeResolved() ); 36 | XProperty generic = contained.getType().getDeclaredProperties( XClass.ACCESS_FIELD ).get( 0 ); 37 | assertTrue( generic.isTypeResolved() ); 38 | } 39 | 40 | public void test2StepsGenericsCollection() throws Exception { 41 | JavaReflectionManager factory = new JavaReflectionManager(); 42 | XClass container = factory.toXClass( ContainerWithCollection.class ); 43 | XProperty collection = container.getDeclaredProperties( XClass.ACCESS_FIELD ).get( 0 ); 44 | assertTrue( collection.isTypeResolved() ); 45 | XClass elementClass = collection.getElementClass(); 46 | XProperty generic = elementClass.getDeclaredProperties( XClass.ACCESS_FIELD ).get( 0 ); 47 | assertTrue( generic.isTypeResolved() ); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/org/hibernate/annotations/common/test/reflection/java/generics/deep/DeepGenericsInheritance.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.test.reflection.java.generics.deep; 6 | 7 | import junit.framework.TestCase; 8 | import org.hibernate.annotations.common.reflection.XClass; 9 | import org.hibernate.annotations.common.reflection.java.JavaReflectionManager; 10 | 11 | 12 | /** 13 | * @author Emmanuel Bernard 14 | */ 15 | public class DeepGenericsInheritance extends TestCase { 16 | public void test2StepsGenerics() throws Exception { 17 | JavaReflectionManager factory = new JavaReflectionManager(); 18 | XClass subclass2 = factory.toXClass( Subclass2.class ); 19 | XClass dummySubclass = factory.toXClass( DummySubclass.class ); 20 | XClass superclass = subclass2.getSuperclass(); 21 | XClass supersuperclass = superclass.getSuperclass(); 22 | assertTrue( supersuperclass.getDeclaredProperties( "field" ).get( 1 ).isTypeResolved() ); 23 | assertEquals( dummySubclass, supersuperclass.getDeclaredProperties( "field" ).get( 1 ).getType() ); 24 | 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/org/hibernate/annotations/common/test/reflection/java/generics/deep/Dummy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.test.reflection.java.generics.deep; 6 | 7 | public class Dummy { 8 | protected Long id; 9 | 10 | private String name; 11 | 12 | 13 | public Long getId() { 14 | return id; 15 | } 16 | 17 | public String getName() { 18 | return name; 19 | } 20 | 21 | public void setName(String name) { 22 | this.name = name; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/test/java/org/hibernate/annotations/common/test/reflection/java/generics/deep/DummySubclass.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.test.reflection.java.generics.deep; 6 | 7 | 8 | public class DummySubclass extends Dummy { 9 | } 10 | -------------------------------------------------------------------------------- /src/test/java/org/hibernate/annotations/common/test/reflection/java/generics/deep/GenericSuperclass1.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.test.reflection.java.generics.deep; 6 | 7 | 8 | public class GenericSuperclass1 { 9 | protected Long id; 10 | 11 | protected T dummy; 12 | 13 | 14 | public Long getId() { 15 | return id; 16 | } 17 | 18 | public T getDummy() { 19 | return dummy; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/org/hibernate/annotations/common/test/reflection/java/generics/deep/GenericSuperclass2.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.test.reflection.java.generics.deep; 6 | 7 | 8 | public class GenericSuperclass2 extends GenericSuperclass1 { 9 | } 10 | -------------------------------------------------------------------------------- /src/test/java/org/hibernate/annotations/common/test/reflection/java/generics/deep/Subclass1.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.test.reflection.java.generics.deep; 6 | 7 | 8 | public class Subclass1 extends GenericSuperclass1 { 9 | } 10 | -------------------------------------------------------------------------------- /src/test/java/org/hibernate/annotations/common/test/reflection/java/generics/deep/Subclass2.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.test.reflection.java.generics.deep; 6 | 7 | 8 | public class Subclass2 extends GenericSuperclass2 { 9 | } 10 | -------------------------------------------------------------------------------- /src/test/java17/org/hibernate/annotations/common/test/reflection/java/records/JavaXPropertyTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * Copyright: Red Hat Inc. and Hibernate Authors 4 | */ 5 | package org.hibernate.annotations.common.test.reflection.java.records; 6 | 7 | import java.util.LinkedList; 8 | import java.util.List; 9 | import junit.framework.TestCase; 10 | import org.hibernate.annotations.common.reflection.ReflectionManager; 11 | import org.hibernate.annotations.common.reflection.XClass; 12 | import org.hibernate.annotations.common.reflection.XProperty; 13 | import org.hibernate.annotations.common.reflection.java.JavaReflectionManager; 14 | 15 | /** 16 | * @author Christian Beikov 17 | */ 18 | public class JavaXPropertyTest extends TestCase { 19 | 20 | private ReflectionManager factory = new JavaReflectionManager(); 21 | 22 | private XClass recordXclass = factory.toXClass( TestRecord.class ); 23 | 24 | public void testFollowsJavaBeansConventionsForPropertyNames() throws Exception { 25 | List properties = new LinkedList(); 26 | properties.add( "id" ); 27 | properties.add( "name" ); 28 | List methodProperties = recordXclass.getDeclaredProperties( XClass.ACCESS_RECORD ); 29 | assertEquals( properties.size(), methodProperties.size() ); 30 | for ( XProperty member : methodProperties ) { 31 | assertTrue( properties.contains( member.getName() ) ); 32 | } 33 | } 34 | 35 | public static record TestRecord(Long id, String name){} 36 | } 37 | -------------------------------------------------------------------------------- /src/test/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | 2 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 3 | log4j.appender.stdout.Target=System.out 4 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 5 | log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n 6 | 7 | log4j.rootLogger=info, stdout 8 | 9 | --------------------------------------------------------------------------------