You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2019/04/27 07:16:12 UTC
[groovy] 03/05: minor refactor: fix CRLF endings
This is an automated email from the ASF dual-hosted git repository.
paulk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git
commit 2b7c9305d40df59dd0fd5600d5fd660edcbc03d4
Author: Paul King <pa...@asert.com.au>
AuthorDate: Sat Apr 27 13:41:33 2019 +1000
minor refactor: fix CRLF endings
---
config/bnd/groovy-all.bnd | 38 +-
config/bnd/groovy.bnd | 38 +-
config/checkstyle/codeHeader.txt | 34 +-
.../java/org/codehaus/groovy/antlr/EnumHelper.java | 136 +-
.../groovy/classgen/AnnotationVisitor.java | 628 ++---
.../codehaus/groovy/classgen/BytecodeSequence.java | 162 +-
.../codehaus/groovy/classgen/ExtendedVerifier.java | 682 +++---
.../groovy/classgen/InnerClassVisitorHelper.java | 286 +--
.../groovy/control/SourceExtensionHandler.java | 132 +-
.../codehaus/groovy/reflection/ParameterTypes.java | 770 +++---
.../codehaus/groovy/runtime/ConversionHandler.java | 444 ++--
.../codehaus/groovy/runtime/ConvertedClosure.java | 108 +-
.../runtime/EncodingGroovyMethodsSupport.java | 180 +-
.../org/codehaus/groovy/runtime/GStringImpl.java | 128 +-
.../groovy/runtime/NumberAwareComparator.java | 112 +-
.../arrays/CharacterArrayPutAtMetaMethod.java | 172 +-
.../dgmimpl/arrays/ObjectArrayPutAtMetaMethod.java | 194 +-
.../runtime/metaclass/ConcurrentReaderHashMap.java | 2542 ++++++++++----------
.../metaclass/MethodSelectionException.java | 202 +-
.../runtime/typehandling/GroovyCastException.java | 174 +-
.../groovy/runtime/typehandling/package.html | 60 +-
.../org/codehaus/groovy/tools/StringHelper.java | 172 +-
.../groovy/transform/AbstractASTTransformUtil.java | 368 +--
.../transform/AbstractASTTransformation.java | 988 ++++----
.../groovy/transform/FieldASTTransformation.java | 584 ++---
.../TupleConstructorASTTransformation.java | 706 +++---
.../codehaus/groovy/util/ComplexKeyHashMap.java | 352 +--
.../org/codehaus/groovy/util/SingleKeyHashMap.java | 322 +--
.../org/codehaus/groovy/util/TripleKeyHashMap.java | 172 +-
.../org/codehaus/groovy/vmplugin/VMPlugin.java | 126 +-
.../vmplugin/v5/PluginDefaultGroovyMethods.java | 292 +--
.../org/codehaus/groovy/vmplugin/v7/Java7.java | 222 +-
src/main/java/overview.html | 82 +-
src/main/java/overviewj.html | 82 +-
.../services/org.codehaus.groovy.source.Extensions | 38 +-
src/test/Outer3.groovy | 44 +-
src/test/Outer4.groovy | 44 +-
src/test/gls/CompilableTestSupport.groovy | 80 +-
src/test/gls/annotations/JavaAnnotation.java | 54 +-
src/test/gls/generics/GenericsTestBase.java | 204 +-
.../invocation/ConstructorDelegationTest.groovy | 312 +--
src/test/gls/invocation/MethodSelectionTest.groovy | 1014 ++++----
src/test/gls/statements/DeclarationTest.groovy | 100 +-
src/test/gls/statements/ReturnTest.groovy | 122 +-
src/test/gls/syntax/AssertTest.groovy | 58 +-
.../gls/syntax/OldClosureSyntaxRemovalTest.groovy | 88 +-
.../gls/syntax/OldPropertySyntaxRemovalTest.groovy | 62 +-
src/test/gls/syntax/OldSpreadTest.groovy | 60 +-
src/test/gls/syntax/ParsingTest.groovy | 170 +-
src/test/groovy/BinaryStreamsTest.groovy | 334 +--
src/test/groovy/ClosureJavaIntegrationTest.java | 414 ++--
src/test/groovy/ClosureMissingMethodTest.groovy | 240 +-
src/test/groovy/CompileOrderTest.groovy | 164 +-
src/test/groovy/FinallyTest.groovy | 300 +--
.../groovy/GroovyCharSequenceMethodsTest.groovy | 784 +++---
src/test/groovy/JointGroovy.groovy | 60 +-
src/test/groovy/JointJava.java | 54 +-
src/test/groovy/KeywordsInPropertyNamesTest.groovy | 288 +--
src/test/groovy/MethodInBadPositionTest.groovy | 88 +-
src/test/groovy/StaticMessageTest.groovy | 76 +-
src/test/groovy/ThisAndSuperTest.groovy | 408 ++--
src/test/groovy/annotations/MyClass.groovy | 54 +-
.../PackageAndImportAnnotationTest.groovy | 80 +-
src/test/groovy/annotations/package-info.groovy | 38 +-
src/test/groovy/bugs/G3839A1.java | 48 +-
src/test/groovy/bugs/G3839A2.java | 50 +-
src/test/groovy/bugs/G3839A3.java | 48 +-
src/test/groovy/bugs/G3839A4.java | 50 +-
src/test/groovy/bugs/G3839Transform1.java | 70 +-
src/test/groovy/bugs/G3839Transform2.java | 70 +-
src/test/groovy/bugs/G3839Transform3.java | 70 +-
src/test/groovy/bugs/G4410Producer1.java | 48 +-
src/test/groovy/bugs/G4410Producer2.java | 50 +-
src/test/groovy/bugs/Groovy1407_Bug.groovy | 86 +-
src/test/groovy/bugs/Groovy1465Bug.groovy | 112 +-
src/test/groovy/bugs/Groovy1593.groovy | 64 +-
src/test/groovy/bugs/Groovy1617_Bug.groovy | 72 +-
src/test/groovy/bugs/Groovy1706_Bug.groovy | 82 +-
src/test/groovy/bugs/Groovy2271Bug.groovy | 94 +-
src/test/groovy/bugs/Groovy2339Bug.groovy | 68 +-
src/test/groovy/bugs/Groovy2849Bug.groovy | 84 +-
src/test/groovy/bugs/Groovy2951Bug.groovy | 106 +-
src/test/groovy/bugs/Groovy3069Bug.groovy | 124 +-
src/test/groovy/bugs/Groovy3135Bug.groovy | 150 +-
src/test/groovy/bugs/Groovy3139Bug.groovy | 112 +-
src/test/groovy/bugs/Groovy3156And2621Bug.groovy | 110 +-
src/test/groovy/bugs/Groovy3205Bug.groovy | 70 +-
src/test/groovy/bugs/Groovy3238Bug.groovy | 78 +-
src/test/groovy/bugs/Groovy3305Bug.groovy | 106 +-
src/test/groovy/bugs/Groovy3311Bug.groovy | 66 +-
src/test/groovy/bugs/Groovy3335Bug.groovy | 54 +-
src/test/groovy/bugs/Groovy3339Bug.groovy | 110 +-
src/test/groovy/bugs/Groovy3383Bug.groovy | 62 +-
src/test/groovy/bugs/Groovy3389Bug.groovy | 70 +-
src/test/groovy/bugs/Groovy3403Bug.groovy | 118 +-
src/test/groovy/bugs/Groovy3405Bug.groovy | 78 +-
src/test/groovy/bugs/Groovy3410Bug.groovy | 164 +-
src/test/groovy/bugs/Groovy3462Bug.groovy | 72 +-
src/test/groovy/bugs/Groovy3465Bug.groovy | 64 +-
src/test/groovy/bugs/Groovy3465Helper.groovy | 56 +-
src/test/groovy/bugs/Groovy3498Bug.groovy | 56 +-
src/test/groovy/bugs/Groovy3511Bug.groovy | 110 +-
src/test/groovy/bugs/Groovy3560Bug.groovy | 52 +-
src/test/groovy/bugs/Groovy3560Helper.java | 66 +-
src/test/groovy/bugs/Groovy3574Bug.groovy | 122 +-
src/test/groovy/bugs/Groovy3590Bug.groovy | 52 +-
src/test/groovy/bugs/Groovy3596Bug.groovy | 60 +-
src/test/groovy/bugs/Groovy3645Bug.groovy | 68 +-
src/test/groovy/bugs/Groovy3658Bug.groovy | 74 +-
src/test/groovy/bugs/Groovy3679Bug.groovy | 96 +-
src/test/groovy/bugs/Groovy3716Bug.groovy | 58 +-
src/test/groovy/bugs/Groovy3718Bug.groovy | 62 +-
src/test/groovy/bugs/Groovy3719Bug.groovy | 62 +-
src/test/groovy/bugs/Groovy3719Bug_script.groovy | 38 +-
src/test/groovy/bugs/Groovy3720Bug.groovy | 128 +-
src/test/groovy/bugs/Groovy3721Bug.groovy | 78 +-
src/test/groovy/bugs/Groovy3723Bug.groovy | 90 +-
src/test/groovy/bugs/Groovy3726Bug.groovy | 126 +-
src/test/groovy/bugs/Groovy3731Bug.groovy | 86 +-
src/test/groovy/bugs/Groovy3749Bug.groovy | 182 +-
src/test/groovy/bugs/Groovy3768Bug.groovy | 100 +-
src/test/groovy/bugs/Groovy3770Bug.groovy | 112 +-
src/test/groovy/bugs/Groovy3776Bug.groovy | 92 +-
src/test/groovy/bugs/Groovy3784Bug.groovy | 74 +-
src/test/groovy/bugs/Groovy3789Bug.groovy | 74 +-
src/test/groovy/bugs/Groovy3799Bug.groovy | 62 +-
src/test/groovy/bugs/Groovy3799Helper.java | 94 +-
src/test/groovy/bugs/Groovy3801Bug.groovy | 106 +-
src/test/groovy/bugs/Groovy3817Bug.groovy | 88 +-
src/test/groovy/bugs/Groovy3818Bug.groovy | 96 +-
src/test/groovy/bugs/Groovy3827Bug.groovy | 76 +-
src/test/groovy/bugs/Groovy3830Bug.groovy | 144 +-
src/test/groovy/bugs/Groovy3831Bug.groovy | 106 +-
src/test/groovy/bugs/Groovy3834Bug.groovy | 72 +-
src/test/groovy/bugs/Groovy3839Bug.groovy | 148 +-
src/test/groovy/bugs/Groovy3852Bug.groovy | 214 +-
src/test/groovy/bugs/Groovy3857Bug.groovy | 60 +-
src/test/groovy/bugs/Groovy3863Bug.groovy | 62 +-
src/test/groovy/bugs/Groovy3868Bug.groovy | 80 +-
src/test/groovy/bugs/Groovy3873Bug.groovy | 66 +-
src/test/groovy/bugs/Groovy3876Bug.groovy | 84 +-
src/test/groovy/bugs/Groovy3894Bug.groovy | 78 +-
src/test/groovy/bugs/Groovy3904Bug.groovy | 168 +-
src/test/groovy/bugs/Groovy3949Bug.groovy | 64 +-
src/test/groovy/bugs/Groovy3989Bug.groovy | 74 +-
src/test/groovy/bugs/Groovy4006Bug.groovy | 298 +--
src/test/groovy/bugs/Groovy4009Bug.groovy | 74 +-
src/test/groovy/bugs/Groovy4025Bug.groovy | 84 +-
src/test/groovy/bugs/Groovy4029Bug.groovy | 54 +-
src/test/groovy/bugs/Groovy4035Bug.groovy | 96 +-
src/test/groovy/bugs/Groovy4038Bug.groovy | 56 +-
src/test/groovy/bugs/Groovy4043Bug.groovy | 68 +-
src/test/groovy/bugs/Groovy4046Bug.groovy | 58 +-
src/test/groovy/bugs/Groovy4069Bug.groovy | 268 +--
src/test/groovy/bugs/Groovy4075Bug.groovy | 82 +-
src/test/groovy/bugs/Groovy4080Bug.groovy | 72 +-
src/test/groovy/bugs/Groovy4081Bug.groovy | 76 +-
src/test/groovy/bugs/Groovy4098Bug.groovy | 296 +--
src/test/groovy/bugs/Groovy4098Child.groovy | 74 +-
src/test/groovy/bugs/Groovy4098Parent.groovy | 50 +-
src/test/groovy/bugs/Groovy4104A.java | 60 +-
src/test/groovy/bugs/Groovy4104B.java | 40 +-
src/test/groovy/bugs/Groovy4104Bug.groovy | 66 +-
src/test/groovy/bugs/Groovy4106Bug.groovy | 54 +-
src/test/groovy/bugs/Groovy4107Bug.groovy | 72 +-
src/test/groovy/bugs/Groovy4111Bug.groovy | 80 +-
src/test/groovy/bugs/Groovy4116Bug.groovy | 130 +-
src/test/groovy/bugs/Groovy4119Bug.groovy | 72 +-
src/test/groovy/bugs/Groovy4120Bug.groovy | 112 +-
src/test/groovy/bugs/Groovy4121Bug.groovy | 94 +-
src/test/groovy/bugs/Groovy4129Bug.groovy | 66 +-
src/test/groovy/bugs/Groovy4131Bug.groovy | 64 +-
src/test/groovy/bugs/Groovy4133Bug.groovy | 64 +-
src/test/groovy/bugs/Groovy4134Bug.groovy | 54 +-
src/test/groovy/bugs/Groovy4139Bug.groovy | 66 +-
src/test/groovy/bugs/Groovy4145.groovy | 48 +-
src/test/groovy/bugs/Groovy4169Bug.groovy | 72 +-
src/test/groovy/bugs/Groovy4170Bug.groovy | 74 +-
src/test/groovy/bugs/Groovy4188Bug.groovy | 76 +-
src/test/groovy/bugs/Groovy4190Bug.groovy | 102 +-
src/test/groovy/bugs/Groovy4191Bug.groovy | 60 +-
src/test/groovy/bugs/Groovy4193Bug.groovy | 60 +-
src/test/groovy/bugs/Groovy4202Bug.groovy | 72 +-
src/test/groovy/bugs/Groovy4206Bug.groovy | 68 +-
src/test/groovy/bugs/Groovy4235Bug.groovy | 64 +-
src/test/groovy/bugs/Groovy4241Bug.groovy | 80 +-
src/test/groovy/bugs/Groovy4243Bug.groovy | 96 +-
src/test/groovy/bugs/Groovy4246Bug.groovy | 94 +-
src/test/groovy/bugs/Groovy4247Bug.groovy | 74 +-
src/test/groovy/bugs/Groovy4252Bug.groovy | 178 +-
src/test/groovy/bugs/Groovy4257Bug.groovy | 80 +-
src/test/groovy/bugs/Groovy4264Bug.groovy | 138 +-
src/test/groovy/bugs/Groovy4272Bug.groovy | 64 +-
src/test/groovy/bugs/Groovy4273Bug.groovy | 130 +-
src/test/groovy/bugs/Groovy4293Bug.groovy | 80 +-
src/test/groovy/bugs/Groovy4325Bug.groovy | 72 +-
src/test/groovy/bugs/Groovy4386_Bug.groovy | 178 +-
src/test/groovy/bugs/Groovy4393Bug.groovy | 56 +-
src/test/groovy/bugs/Groovy4393BugV1.foogroovy | 40 +-
src/test/groovy/bugs/Groovy4410Bug.groovy | 124 +-
src/test/groovy/bugs/Groovy4414Bug.groovy | 138 +-
src/test/groovy/bugs/Groovy4416Bug.groovy | 78 +-
src/test/groovy/bugs/Groovy4435Bug.groovy | 78 +-
src/test/groovy/bugs/Groovy4449Bug.groovy | 88 +-
src/test/groovy/bugs/Groovy4497Bug.groovy | 78 +-
src/test/groovy/bugs/Groovy4516Bug.groovy | 78 +-
src/test/groovy/bugs/Groovy4584Bug.groovy | 72 +-
src/test/groovy/bugs/Groovy4607Bug.groovy | 104 +-
src/test/groovy/bugs/Groovy4861Bug.groovy | 74 +-
src/test/groovy/bugs/Groovy513_Bug.groovy | 72 +-
src/test/groovy/bugs/GroovyInnerEnumBug.groovy | 94 +-
.../groovy/grape/GrabErrorIsolationTest.groovy | 112 +-
src/test/groovy/grape/GrapeClassLoaderTest.groovy | 568 ++---
src/test/groovy/lang/CategoryAnnotationTest.groovy | 596 ++---
src/test/groovy/lang/Groovy3406Test.groovy | 52 +-
.../groovy/lang/InnerClassResolvingTest.groovy | 122 +-
src/test/groovy/lang/StripMarginTest.groovy | 186 +-
.../groovy/mock/interceptor/HalfMockTest.groovy | 284 +--
.../groovy/mock/interceptor/IteratorCounter.java | 52 +-
.../groovy/mock/interceptor/MockForJavaTest.groovy | 108 +-
.../mock/interceptor/MockNestedCallTest.groovy | 90 +-
.../groovy/mock/interceptor/StubForJavaTest.groovy | 100 +-
src/test/groovy/util/ResourceBundleTest.groovy | 154 +-
src/test/groovy/util/i18n.properties | 40 +-
src/test/groovy/util/i18n_fr.properties | 40 +-
src/test/groovy/util/logging/LogTest.groovy | 888 +++----
.../codehaus/groovy/antlr/SourceParserTest.java | 104 +-
.../org/codehaus/groovy/ast/LineColumnCheck.txt | 534 ++--
.../codehaus/groovy/ast/builder/AstAssert.groovy | 756 +++---
.../groovy/ast/expr/MapExpressionTest.groovy | 88 +-
.../groovy/classgen/ReflectorLoaderTest.groovy | 64 +-
.../reflection/utils/PojoCallerTestClass.java | 66 +-
.../reflection/utils/ReflectionUtilsTest.groovy | 192 +-
.../groovy/runtime/MetaClassHelperTest.java | 54 +-
.../groovy/runtime/NestedCategoryTest.groovy | 158 +-
.../groovy/tools/LoaderConfigurationTest.groovy | 276 +--
.../codehaus/groovy/tools/StringHelperTest.groovy | 70 +-
.../org/codehaus/groovy/tools/UtilitiesTest.groovy | 84 +-
.../AbstractGenericGroovySuperclass.groovy | 68 +-
.../rootloadersync/AbstractGroovySuperclass.groovy | 54 +-
.../ConcreteGenericJavaSubclass.java | 64 +-
.../tools/rootloadersync/ConcreteJavaSubclass.java | 52 +-
.../OtherConcreteGenericJavaSubclass.java | 64 +-
.../rootloadersync/OtherConcreteJavaSubclass.java | 52 +-
.../rootloadersync/SubclassingInGroovyTest.groovy | 78 +-
.../rootloadersync/SubclassingInJavaTest.java | 82 +-
.../groovy/transform/CanonicalTransformTest.groovy | 1184 ++++-----
.../groovy/transform/FieldTransformTest.groovy | 572 ++---
.../groovy/transform/GlobalTransformTest.groovy | 70 +-
.../transform/IndexedPropertyTransformTest.groovy | 148 +-
.../groovy/transform/LazyTransformTest.groovy | 446 ++--
...org.codehaus.groovy.transform.ASTTransformation | 34 +-
.../groovy/transform/NewifyTransformTest.groovy | 474 ++--
.../codehaus/groovy/transform/TestTransform.groovy | 96 +-
.../jmx/builder/JmxAttributeInfoManager.groovy | 180 +-
.../groovy/jmx/builder/JmxBeanExportFactory.groovy | 106 +-
.../groovy/jmx/builder/JmxBeanFactory.groovy | 326 +--
.../groovy/jmx/builder/JmxBeanInfoManager.groovy | 190 +-
.../groovy/groovy/jmx/builder/JmxBuilder.groovy | 208 +-
.../groovy/jmx/builder/JmxBuilderTools.groovy | 636 ++---
.../jmx/builder/JmxClientConnectorFactory.groovy | 146 +-
.../groovy/jmx/builder/JmxEmitterFactory.groovy | 222 +-
.../groovy/jmx/builder/JmxListenerFactory.groovy | 158 +-
.../groovy/jmx/builder/JmxMetaMapBuilder.groovy | 1294 +++++-----
.../jmx/builder/JmxOperationInfoManager.groovy | 436 ++--
.../jmx/builder/JmxServerConnectorFactory.groovy | 276 +--
.../groovy/jmx/builder/JmxTimerFactory.groovy | 396 +--
.../groovy/groovy/jmx/builder/package-info.groovy | 44 +-
.../groovy/jmx/builder/JmxBuilderException.java | 116 +-
.../groovy/jmx/builder/JmxBuilderModelMBean.java | 442 ++--
.../java/groovy/jmx/builder/JmxEventEmitter.java | 212 +-
.../groovy/jmx/builder/JmxEventEmitterMBean.java | 98 +-
.../java/groovy/jmx/builder/JmxEventListener.java | 160 +-
.../jmx/builder/JmxAttributeInfoManagerTest.groovy | 126 +-
.../jmx/builder/JmxBeanExportFactoryTest.groovy | 1124 ++++-----
.../groovy/jmx/builder/JmxBeanFactoryTest.groovy | 184 +-
.../jmx/builder/JmxBeanInfoManagerTest.groovy | 148 +-
.../groovy/jmx/builder/JmxBuilderToolsTest.groovy | 260 +-
.../builder/JmxClientConnectorFactoryTest.groovy | 142 +-
.../jmx/builder/JmxEmitterFactoryTest.groovy | 198 +-
.../jmx/builder/JmxListenerFactoryTest.groovy | 122 +-
.../jmx/builder/JmxMetaMapBuilderTest.groovy | 1020 ++++----
.../jmx/builder/JmxOperationInfoManagerTest.groovy | 376 +--
.../builder/JmxServerConnectorFactoryTest.groovy | 120 +-
.../groovy/jmx/builder/JmxTimerFactoryTest.groovy | 306 +--
.../jmx/builder/MockManagedGroovyObject.groovy | 74 +-
.../groovy/jmx/builder/JmxConnectorHelper.java | 132 +-
.../java/groovy/jmx/builder/MockJmxListener.java | 98 +-
.../java/groovy/jmx/builder/MockManagedObject.java | 162 +-
.../java/groovy/jmx/builder/MockSimpleObject.java | 80 +-
.../groovy/jmx/builder/MockSimpleObjectMBean.java | 58 +-
.../groovy/text/TemplateExecutionException.java | 112 +-
.../groovy/text/StreamingTemplateEngineTest.groovy | 924 +++----
293 files changed, 25620 insertions(+), 25620 deletions(-)
diff --git a/config/bnd/groovy-all.bnd b/config/bnd/groovy-all.bnd
index 3de9d83..cab706f 100644
--- a/config/bnd/groovy-all.bnd
+++ b/config/bnd/groovy-all.bnd
@@ -1,19 +1,19 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements. See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-version= @GROOVY_BUNDLE_VERSION@
--nouses= true
-Export-Package= *;version=${version}
-Import-Package= *;resolution:=optional
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+version= @GROOVY_BUNDLE_VERSION@
+-nouses= true
+Export-Package= *;version=${version}
+Import-Package= *;resolution:=optional
diff --git a/config/bnd/groovy.bnd b/config/bnd/groovy.bnd
index 2a5f8e3..f5df535 100644
--- a/config/bnd/groovy.bnd
+++ b/config/bnd/groovy.bnd
@@ -1,19 +1,19 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements. See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-version= @GROOVY_BUNDLE_VERSION@
--nouses= true
-Export-Package= *;version=${version}
-Import-Package= antlr, org.objectweb.asm, *;resolution:=optional
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+version= @GROOVY_BUNDLE_VERSION@
+-nouses= true
+Export-Package= *;version=${version}
+Import-Package= antlr, org.objectweb.asm, *;resolution:=optional
diff --git a/config/checkstyle/codeHeader.txt b/config/checkstyle/codeHeader.txt
index 3673647..ca35f1a 100644
--- a/config/checkstyle/codeHeader.txt
+++ b/config/checkstyle/codeHeader.txt
@@ -1,18 +1,18 @@
-^/\*$
-^ \* ? Licensed to the Apache Software Foundation \(ASF\) under one$
-^ \* ? or more contributor license agreements\. See the NOTICE file$
-^ \* ? distributed with this work for additional information$
-^ \* ? regarding copyright ownership\. The ASF licenses this file$
-^ \* ? to you under the Apache License, Version 2\.0 \(the$
-^ \* ? "License"\); you may not use this file except in compliance$
-^ \* ? with the License\. You may obtain a copy of the License at$
-^ \*$
-^ \* ? http://www\.apache\.org/licenses/LICENSE-2\.0$
-^ \*$
-^ \* ? Unless required by applicable law or agreed to in writing,$
-^ \* ? software distributed under the License is distributed on an$
-^ \* ? "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY$
-^ \* ? KIND, either express or implied\. See the License for the$
-^ \* ? specific language governing permissions and limitations$
-^ \* ? under the License\.$
+^/\*$
+^ \* ? Licensed to the Apache Software Foundation \(ASF\) under one$
+^ \* ? or more contributor license agreements\. See the NOTICE file$
+^ \* ? distributed with this work for additional information$
+^ \* ? regarding copyright ownership\. The ASF licenses this file$
+^ \* ? to you under the Apache License, Version 2\.0 \(the$
+^ \* ? "License"\); you may not use this file except in compliance$
+^ \* ? with the License\. You may obtain a copy of the License at$
+^ \*$
+^ \* ? http://www\.apache\.org/licenses/LICENSE-2\.0$
+^ \*$
+^ \* ? Unless required by applicable law or agreed to in writing,$
+^ \* ? software distributed under the License is distributed on an$
+^ \* ? "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY$
+^ \* ? KIND, either express or implied\. See the License for the$
+^ \* ? specific language governing permissions and limitations$
+^ \* ? under the License\.$
^ \*.*
\ No newline at end of file
diff --git a/src/main/java/org/codehaus/groovy/antlr/EnumHelper.java b/src/main/java/org/codehaus/groovy/antlr/EnumHelper.java
index 6f5fc3e..803bd0b 100644
--- a/src/main/java/org/codehaus/groovy/antlr/EnumHelper.java
+++ b/src/main/java/org/codehaus/groovy/antlr/EnumHelper.java
@@ -1,68 +1,68 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.codehaus.groovy.antlr;
-
-import org.codehaus.groovy.ast.ClassHelper;
-import org.codehaus.groovy.ast.ClassNode;
-import org.codehaus.groovy.ast.FieldNode;
-import org.codehaus.groovy.ast.GenericsType;
-import org.codehaus.groovy.ast.InnerClassNode;
-import org.codehaus.groovy.ast.MixinNode;
-import org.codehaus.groovy.ast.expr.Expression;
-import org.codehaus.groovy.ast.expr.ListExpression;
-import org.objectweb.asm.Opcodes;
-
-public class EnumHelper {
- private static final int FS = Opcodes.ACC_FINAL | Opcodes.ACC_STATIC;
- private static final int PUBLIC_FS = Opcodes.ACC_PUBLIC | FS;
-
- public static ClassNode makeEnumNode(String name, int modifiers, ClassNode[] interfaces, ClassNode outerClass) {
- modifiers = modifiers | Opcodes.ACC_FINAL | Opcodes.ACC_ENUM;
- ClassNode enumClass;
- if (outerClass==null) {
- enumClass = new ClassNode(name,modifiers,null,interfaces,MixinNode.EMPTY_ARRAY);
- } else {
- name = outerClass.getName() + "$" + name;
- modifiers |= Opcodes.ACC_STATIC;
- enumClass = new InnerClassNode(outerClass,name,modifiers,null,interfaces,MixinNode.EMPTY_ARRAY);
- }
-
- // set super class and generics info
- // "enum X" -> class X extends Enum<X>
- GenericsType gt = new GenericsType(enumClass);
- ClassNode superClass = ClassHelper.makeWithoutCaching("java.lang.Enum");
- superClass.setGenericsTypes(new GenericsType[]{gt});
- enumClass.setSuperClass(superClass);
- superClass.setRedirect(ClassHelper.Enum_Type);
-
- return enumClass;
- }
-
- public static FieldNode addEnumConstant(ClassNode enumClass, String name, Expression init) {
- int modifiers = PUBLIC_FS | Opcodes.ACC_ENUM;
- if (init != null && !(init instanceof ListExpression)) {
- ListExpression list = new ListExpression();
- list.addExpression(init);
- init = list;
- }
- FieldNode fn = new FieldNode(name, modifiers, enumClass.getPlainNodeReference(), enumClass, init);
- enumClass.addField(fn);
- return fn;
- }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.codehaus.groovy.antlr;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.GenericsType;
+import org.codehaus.groovy.ast.InnerClassNode;
+import org.codehaus.groovy.ast.MixinNode;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.ListExpression;
+import org.objectweb.asm.Opcodes;
+
+public class EnumHelper {
+ private static final int FS = Opcodes.ACC_FINAL | Opcodes.ACC_STATIC;
+ private static final int PUBLIC_FS = Opcodes.ACC_PUBLIC | FS;
+
+ public static ClassNode makeEnumNode(String name, int modifiers, ClassNode[] interfaces, ClassNode outerClass) {
+ modifiers = modifiers | Opcodes.ACC_FINAL | Opcodes.ACC_ENUM;
+ ClassNode enumClass;
+ if (outerClass==null) {
+ enumClass = new ClassNode(name,modifiers,null,interfaces,MixinNode.EMPTY_ARRAY);
+ } else {
+ name = outerClass.getName() + "$" + name;
+ modifiers |= Opcodes.ACC_STATIC;
+ enumClass = new InnerClassNode(outerClass,name,modifiers,null,interfaces,MixinNode.EMPTY_ARRAY);
+ }
+
+ // set super class and generics info
+ // "enum X" -> class X extends Enum<X>
+ GenericsType gt = new GenericsType(enumClass);
+ ClassNode superClass = ClassHelper.makeWithoutCaching("java.lang.Enum");
+ superClass.setGenericsTypes(new GenericsType[]{gt});
+ enumClass.setSuperClass(superClass);
+ superClass.setRedirect(ClassHelper.Enum_Type);
+
+ return enumClass;
+ }
+
+ public static FieldNode addEnumConstant(ClassNode enumClass, String name, Expression init) {
+ int modifiers = PUBLIC_FS | Opcodes.ACC_ENUM;
+ if (init != null && !(init instanceof ListExpression)) {
+ ListExpression list = new ListExpression();
+ list.addExpression(init);
+ init = list;
+ }
+ FieldNode fn = new FieldNode(name, modifiers, enumClass.getPlainNodeReference(), enumClass, init);
+ enumClass.addField(fn);
+ return fn;
+ }
+}
diff --git a/src/main/java/org/codehaus/groovy/classgen/AnnotationVisitor.java b/src/main/java/org/codehaus/groovy/classgen/AnnotationVisitor.java
index 46c471e..42eb463 100644
--- a/src/main/java/org/codehaus/groovy/classgen/AnnotationVisitor.java
+++ b/src/main/java/org/codehaus/groovy/classgen/AnnotationVisitor.java
@@ -1,314 +1,314 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.codehaus.groovy.classgen;
-
-import org.codehaus.groovy.ast.ASTNode;
-import org.codehaus.groovy.ast.AnnotationNode;
-import org.codehaus.groovy.ast.ClassHelper;
-import org.codehaus.groovy.ast.ClassNode;
-import org.codehaus.groovy.ast.FieldNode;
-import org.codehaus.groovy.ast.MethodNode;
-import org.codehaus.groovy.ast.expr.AnnotationConstantExpression;
-import org.codehaus.groovy.ast.expr.ClassExpression;
-import org.codehaus.groovy.ast.expr.ClosureExpression;
-import org.codehaus.groovy.ast.expr.ConstantExpression;
-import org.codehaus.groovy.ast.expr.Expression;
-import org.codehaus.groovy.ast.expr.ListExpression;
-import org.codehaus.groovy.ast.expr.PropertyExpression;
-import org.codehaus.groovy.ast.expr.VariableExpression;
-import org.codehaus.groovy.ast.stmt.ReturnStatement;
-import org.codehaus.groovy.control.ErrorCollector;
-import org.codehaus.groovy.control.SourceUnit;
-import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
-import org.codehaus.groovy.syntax.SyntaxException;
-import org.codehaus.groovy.vmplugin.VMPluginFactory;
-
-import java.util.List;
-import java.util.Map;
-
-import static org.apache.groovy.ast.tools.ExpressionUtils.transformInlineConstants;
-
-/**
- * An Annotation visitor responsible for:
- * <ul>
- * <li>reading annotation metadata (@Retention, @Target, attribute types)</li>
- * <li>verify that an <code>AnnotationNode</code> conforms to annotation meta</li>
- * <li>enhancing an <code>AnnotationNode</code> AST to reflect real annotation meta</li>
- * </ul>
- */
-public class AnnotationVisitor {
- private final SourceUnit source;
- private final ErrorCollector errorCollector;
- private AnnotationNode annotation;
- private ClassNode reportClass;
-
- public AnnotationVisitor(SourceUnit source, ErrorCollector errorCollector) {
- this.source = source;
- this.errorCollector = errorCollector;
- }
-
- public void setReportClass(ClassNode cn) {
- reportClass = cn;
- }
-
- public AnnotationNode visit(AnnotationNode node) {
- this.annotation = node;
- this.reportClass = node.getClassNode();
-
- if (!isValidAnnotationClass(node.getClassNode())) {
- addError("class " + node.getClassNode().getName() + " is not an annotation");
- return node;
- }
-
- // check if values have been passed for all annotation attributes that don't have defaults
- if (!checkIfMandatoryAnnotationValuesPassed(node)) {
- return node;
- }
-
- // if enum constants have been used, check if they are all valid
- if (!checkIfValidEnumConstsAreUsed(node)) {
- return node;
- }
-
- Map<String, Expression> attributes = node.getMembers();
- for (Map.Entry<String, Expression> entry : attributes.entrySet()) {
- String attrName = entry.getKey();
- ClassNode attrType = getAttributeType(node, attrName);
- Expression attrExpr = transformInlineConstants(entry.getValue(), attrType);
- entry.setValue(attrExpr);
- visitExpression(attrName, attrExpr, attrType);
- }
- VMPluginFactory.getPlugin().configureAnnotation(node);
- return this.annotation;
- }
-
- private boolean checkIfValidEnumConstsAreUsed(AnnotationNode node) {
- Map<String, Expression> attributes = node.getMembers();
- for (Map.Entry<String, Expression> entry : attributes.entrySet()) {
- if (!validateEnumConstant(entry.getValue()))
- return false;
- }
- return true;
- }
-
- private boolean validateEnumConstant(Expression exp) {
- if (exp instanceof PropertyExpression) {
- PropertyExpression pe = (PropertyExpression) exp;
- String name = pe.getPropertyAsString();
- if (pe.getObjectExpression() instanceof ClassExpression && name != null) {
- ClassExpression ce = (ClassExpression) pe.getObjectExpression();
- ClassNode type = ce.getType();
- if (type.isEnum()) {
- boolean ok = false;
- try {
- FieldNode enumField = type.getDeclaredField(name);
- ok = enumField != null && enumField.getType().equals(type);
- } catch(Exception ex) {
- // ignore
- }
- if(!ok) {
- addError("No enum const " + type.getName() + "." + name, pe);
- return false;
- }
- }
- }
- }
- return true;
- }
-
- private boolean checkIfMandatoryAnnotationValuesPassed(AnnotationNode node) {
- boolean ok = true;
- Map attributes = node.getMembers();
- ClassNode classNode = node.getClassNode();
- for (MethodNode mn : classNode.getMethods()) {
- String methodName = mn.getName();
- // if the annotation attribute has a default, getCode() returns a ReturnStatement with the default value
- if (mn.getCode() == null && !attributes.containsKey(methodName)) {
- addError("No explicit/default value found for annotation attribute '" + methodName + "'", node);
- ok = false;
- }
- }
- return ok;
- }
-
- private ClassNode getAttributeType(AnnotationNode node, String attrName) {
- ClassNode classNode = node.getClassNode();
- List methods = classNode.getMethods(attrName);
- // if size is >1, then the method was overwritten or something, we ignore that
- // if it is an error, we have to test it at another place. But size==0 is
- // an error, because it means that no such attribute exists.
- if (methods.isEmpty()) {
- addError("'" + attrName + "'is not part of the annotation " + classNode, node);
- return ClassHelper.OBJECT_TYPE;
- }
- MethodNode method = (MethodNode) methods.get(0);
- return method.getReturnType();
- }
-
- private static boolean isValidAnnotationClass(ClassNode node) {
- return node.implementsInterface(ClassHelper.Annotation_TYPE);
- }
-
- protected void visitExpression(String attrName, Expression attrExp, ClassNode attrType) {
- if (attrType.isArray()) {
- // check needed as @Test(attr = {"elem"}) passes through the parser
- if (attrExp instanceof ListExpression) {
- ListExpression le = (ListExpression) attrExp;
- visitListExpression(attrName, le, attrType.getComponentType());
- } else if (attrExp instanceof ClosureExpression) {
- addError("Annotation list attributes must use Groovy notation [el1, el2]", attrExp);
- } else {
- // treat like a singleton list as per Java
- ListExpression listExp = new ListExpression();
- listExp.addExpression(attrExp);
- if (annotation != null) {
- annotation.setMember(attrName, listExp);
- }
- visitExpression(attrName, listExp, attrType);
- }
- } else if (ClassHelper.isPrimitiveType(attrType)) {
- visitConstantExpression(attrName, getConstantExpression(attrExp, attrType), ClassHelper.getWrapper(attrType));
- } else if (ClassHelper.STRING_TYPE.equals(attrType)) {
- visitConstantExpression(attrName, getConstantExpression(attrExp, attrType), ClassHelper.STRING_TYPE);
- } else if (ClassHelper.CLASS_Type.equals(attrType)) {
- if (!(attrExp instanceof ClassExpression || attrExp instanceof ClosureExpression)) {
- addError("Only classes and closures can be used for attribute '" + attrName + "'", attrExp);
- }
- } else if (attrType.isDerivedFrom(ClassHelper.Enum_Type)) {
- if (attrExp instanceof PropertyExpression) {
- visitEnumExpression(attrName, (PropertyExpression) attrExp, attrType);
- } else {
- addError("Expected enum value for attribute " + attrName, attrExp);
- }
- } else if (isValidAnnotationClass(attrType)) {
- if (attrExp instanceof AnnotationConstantExpression) {
- visitAnnotationExpression(attrName, (AnnotationConstantExpression) attrExp, attrType);
- } else {
- addError("Expected annotation of type '" + attrType.getName() + "' for attribute " + attrName, attrExp);
- }
- } else {
- addError("Unexpected type " + attrType.getName(), attrExp);
- }
- }
-
- public void checkReturnType(ClassNode attrType, ASTNode node) {
- if (attrType.isArray()) {
- checkReturnType(attrType.getComponentType(), node);
- } else if (ClassHelper.isPrimitiveType(attrType)) {
- } else if (ClassHelper.STRING_TYPE.equals(attrType)) {
- } else if (ClassHelper.CLASS_Type.equals(attrType)) {
- } else if (attrType.isDerivedFrom(ClassHelper.Enum_Type)) {
- } else if (isValidAnnotationClass(attrType)) {
- } else {
- addError("Unexpected return type " + attrType.getName(), node);
- }
- }
-
- private ConstantExpression getConstantExpression(Expression exp, ClassNode attrType) {
- Expression result = exp;
- if (!(result instanceof ConstantExpression)) {
- result = transformInlineConstants(result, attrType);
- }
- if (result instanceof ConstantExpression) {
- return (ConstantExpression) result;
- }
- String base = "Expected '" + exp.getText() + "' to be an inline constant of type " + attrType.getName();
- if (exp instanceof PropertyExpression) {
- addError(base + " not a property expression", exp);
- } else if (exp instanceof VariableExpression && ((VariableExpression)exp).getAccessedVariable() instanceof FieldNode) {
- addError(base + " not a field expression", exp);
- } else {
- addError(base, exp);
- }
- return ConstantExpression.EMPTY_EXPRESSION;
- }
-
- /**
- * @param attrName the name
- * @param expression the expression
- * @param attrType the type
- */
- protected void visitAnnotationExpression(String attrName, AnnotationConstantExpression expression, ClassNode attrType) {
- AnnotationNode annotationNode = (AnnotationNode) expression.getValue();
- AnnotationVisitor visitor = new AnnotationVisitor(this.source, this.errorCollector);
- // TODO track Deprecated usage and give a warning?
- visitor.visit(annotationNode);
- }
-
- protected void visitListExpression(String attrName, ListExpression listExpr, ClassNode elementType) {
- for (Expression expression : listExpr.getExpressions()) {
- visitExpression(attrName, expression, elementType);
- }
- }
-
- protected void visitConstantExpression(String attrName, ConstantExpression constExpr, ClassNode attrType) {
- ClassNode constType = constExpr.getType();
- ClassNode wrapperType = ClassHelper.getWrapper(constType);
- if (!hasCompatibleType(attrType, wrapperType)) {
- addError("Attribute '" + attrName + "' should have type '" + attrType.getName()
- + "'; but found type '" + constType.getName() + "'", constExpr);
- }
- }
-
- private static boolean hasCompatibleType(ClassNode attrType, ClassNode wrapperType) {
- return wrapperType.isDerivedFrom(ClassHelper.getWrapper(attrType));
- }
-
- protected void visitEnumExpression(String attrName, PropertyExpression propExpr, ClassNode attrType) {
- if (!propExpr.getObjectExpression().getType().isDerivedFrom(attrType)) {
- addError("Attribute '" + attrName + "' should have type '" + attrType.getName() + "' (Enum), but found "
- + propExpr.getObjectExpression().getType().getName(),
- propExpr);
- }
- }
-
- protected void addError(String msg) {
- addError(msg, this.annotation);
- }
-
- protected void addError(String msg, ASTNode expr) {
- this.errorCollector.addErrorAndContinue(
- new SyntaxErrorMessage(new SyntaxException(msg + " in @" + this.reportClass.getName() + '\n', expr.getLineNumber(), expr.getColumnNumber(), expr.getLastLineNumber(), expr.getLastColumnNumber()), this.source)
- );
- }
-
- public void checkCircularReference(ClassNode searchClass, ClassNode attrType, Expression startExp) {
- if (!isValidAnnotationClass(attrType)) return;
- if (!(startExp instanceof AnnotationConstantExpression)) {
- addError("Found '" + startExp.getText() + "' when expecting an Annotation Constant", startExp);
- return;
- }
- AnnotationConstantExpression ace = (AnnotationConstantExpression) startExp;
- AnnotationNode annotationNode = (AnnotationNode) ace.getValue();
- if (annotationNode.getClassNode().equals(searchClass)) {
- addError("Circular reference discovered in " + searchClass.getName(), startExp);
- return;
- }
- ClassNode cn = annotationNode.getClassNode();
- for (MethodNode method : cn.getMethods()) {
- if (method.getReturnType().equals(searchClass)) {
- addError("Circular reference discovered in " + cn.getName(), startExp);
- }
- ReturnStatement code = (ReturnStatement) method.getCode();
- if (code == null) continue;
- checkCircularReference(searchClass, method.getReturnType(), code.getExpression());
- }
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.codehaus.groovy.classgen;
+
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.AnnotationNode;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.expr.AnnotationConstantExpression;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.ClosureExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.ListExpression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.stmt.ReturnStatement;
+import org.codehaus.groovy.control.ErrorCollector;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
+import org.codehaus.groovy.syntax.SyntaxException;
+import org.codehaus.groovy.vmplugin.VMPluginFactory;
+
+import java.util.List;
+import java.util.Map;
+
+import static org.apache.groovy.ast.tools.ExpressionUtils.transformInlineConstants;
+
+/**
+ * An Annotation visitor responsible for:
+ * <ul>
+ * <li>reading annotation metadata (@Retention, @Target, attribute types)</li>
+ * <li>verify that an <code>AnnotationNode</code> conforms to annotation meta</li>
+ * <li>enhancing an <code>AnnotationNode</code> AST to reflect real annotation meta</li>
+ * </ul>
+ */
+public class AnnotationVisitor {
+ private final SourceUnit source;
+ private final ErrorCollector errorCollector;
+ private AnnotationNode annotation;
+ private ClassNode reportClass;
+
+ public AnnotationVisitor(SourceUnit source, ErrorCollector errorCollector) {
+ this.source = source;
+ this.errorCollector = errorCollector;
+ }
+
+ public void setReportClass(ClassNode cn) {
+ reportClass = cn;
+ }
+
+ public AnnotationNode visit(AnnotationNode node) {
+ this.annotation = node;
+ this.reportClass = node.getClassNode();
+
+ if (!isValidAnnotationClass(node.getClassNode())) {
+ addError("class " + node.getClassNode().getName() + " is not an annotation");
+ return node;
+ }
+
+ // check if values have been passed for all annotation attributes that don't have defaults
+ if (!checkIfMandatoryAnnotationValuesPassed(node)) {
+ return node;
+ }
+
+ // if enum constants have been used, check if they are all valid
+ if (!checkIfValidEnumConstsAreUsed(node)) {
+ return node;
+ }
+
+ Map<String, Expression> attributes = node.getMembers();
+ for (Map.Entry<String, Expression> entry : attributes.entrySet()) {
+ String attrName = entry.getKey();
+ ClassNode attrType = getAttributeType(node, attrName);
+ Expression attrExpr = transformInlineConstants(entry.getValue(), attrType);
+ entry.setValue(attrExpr);
+ visitExpression(attrName, attrExpr, attrType);
+ }
+ VMPluginFactory.getPlugin().configureAnnotation(node);
+ return this.annotation;
+ }
+
+ private boolean checkIfValidEnumConstsAreUsed(AnnotationNode node) {
+ Map<String, Expression> attributes = node.getMembers();
+ for (Map.Entry<String, Expression> entry : attributes.entrySet()) {
+ if (!validateEnumConstant(entry.getValue()))
+ return false;
+ }
+ return true;
+ }
+
+ private boolean validateEnumConstant(Expression exp) {
+ if (exp instanceof PropertyExpression) {
+ PropertyExpression pe = (PropertyExpression) exp;
+ String name = pe.getPropertyAsString();
+ if (pe.getObjectExpression() instanceof ClassExpression && name != null) {
+ ClassExpression ce = (ClassExpression) pe.getObjectExpression();
+ ClassNode type = ce.getType();
+ if (type.isEnum()) {
+ boolean ok = false;
+ try {
+ FieldNode enumField = type.getDeclaredField(name);
+ ok = enumField != null && enumField.getType().equals(type);
+ } catch(Exception ex) {
+ // ignore
+ }
+ if(!ok) {
+ addError("No enum const " + type.getName() + "." + name, pe);
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ private boolean checkIfMandatoryAnnotationValuesPassed(AnnotationNode node) {
+ boolean ok = true;
+ Map attributes = node.getMembers();
+ ClassNode classNode = node.getClassNode();
+ for (MethodNode mn : classNode.getMethods()) {
+ String methodName = mn.getName();
+ // if the annotation attribute has a default, getCode() returns a ReturnStatement with the default value
+ if (mn.getCode() == null && !attributes.containsKey(methodName)) {
+ addError("No explicit/default value found for annotation attribute '" + methodName + "'", node);
+ ok = false;
+ }
+ }
+ return ok;
+ }
+
+ private ClassNode getAttributeType(AnnotationNode node, String attrName) {
+ ClassNode classNode = node.getClassNode();
+ List methods = classNode.getMethods(attrName);
+ // if size is >1, then the method was overwritten or something, we ignore that
+ // if it is an error, we have to test it at another place. But size==0 is
+ // an error, because it means that no such attribute exists.
+ if (methods.isEmpty()) {
+ addError("'" + attrName + "'is not part of the annotation " + classNode, node);
+ return ClassHelper.OBJECT_TYPE;
+ }
+ MethodNode method = (MethodNode) methods.get(0);
+ return method.getReturnType();
+ }
+
+ private static boolean isValidAnnotationClass(ClassNode node) {
+ return node.implementsInterface(ClassHelper.Annotation_TYPE);
+ }
+
+ protected void visitExpression(String attrName, Expression attrExp, ClassNode attrType) {
+ if (attrType.isArray()) {
+ // check needed as @Test(attr = {"elem"}) passes through the parser
+ if (attrExp instanceof ListExpression) {
+ ListExpression le = (ListExpression) attrExp;
+ visitListExpression(attrName, le, attrType.getComponentType());
+ } else if (attrExp instanceof ClosureExpression) {
+ addError("Annotation list attributes must use Groovy notation [el1, el2]", attrExp);
+ } else {
+ // treat like a singleton list as per Java
+ ListExpression listExp = new ListExpression();
+ listExp.addExpression(attrExp);
+ if (annotation != null) {
+ annotation.setMember(attrName, listExp);
+ }
+ visitExpression(attrName, listExp, attrType);
+ }
+ } else if (ClassHelper.isPrimitiveType(attrType)) {
+ visitConstantExpression(attrName, getConstantExpression(attrExp, attrType), ClassHelper.getWrapper(attrType));
+ } else if (ClassHelper.STRING_TYPE.equals(attrType)) {
+ visitConstantExpression(attrName, getConstantExpression(attrExp, attrType), ClassHelper.STRING_TYPE);
+ } else if (ClassHelper.CLASS_Type.equals(attrType)) {
+ if (!(attrExp instanceof ClassExpression || attrExp instanceof ClosureExpression)) {
+ addError("Only classes and closures can be used for attribute '" + attrName + "'", attrExp);
+ }
+ } else if (attrType.isDerivedFrom(ClassHelper.Enum_Type)) {
+ if (attrExp instanceof PropertyExpression) {
+ visitEnumExpression(attrName, (PropertyExpression) attrExp, attrType);
+ } else {
+ addError("Expected enum value for attribute " + attrName, attrExp);
+ }
+ } else if (isValidAnnotationClass(attrType)) {
+ if (attrExp instanceof AnnotationConstantExpression) {
+ visitAnnotationExpression(attrName, (AnnotationConstantExpression) attrExp, attrType);
+ } else {
+ addError("Expected annotation of type '" + attrType.getName() + "' for attribute " + attrName, attrExp);
+ }
+ } else {
+ addError("Unexpected type " + attrType.getName(), attrExp);
+ }
+ }
+
+ public void checkReturnType(ClassNode attrType, ASTNode node) {
+ if (attrType.isArray()) {
+ checkReturnType(attrType.getComponentType(), node);
+ } else if (ClassHelper.isPrimitiveType(attrType)) {
+ } else if (ClassHelper.STRING_TYPE.equals(attrType)) {
+ } else if (ClassHelper.CLASS_Type.equals(attrType)) {
+ } else if (attrType.isDerivedFrom(ClassHelper.Enum_Type)) {
+ } else if (isValidAnnotationClass(attrType)) {
+ } else {
+ addError("Unexpected return type " + attrType.getName(), node);
+ }
+ }
+
+ private ConstantExpression getConstantExpression(Expression exp, ClassNode attrType) {
+ Expression result = exp;
+ if (!(result instanceof ConstantExpression)) {
+ result = transformInlineConstants(result, attrType);
+ }
+ if (result instanceof ConstantExpression) {
+ return (ConstantExpression) result;
+ }
+ String base = "Expected '" + exp.getText() + "' to be an inline constant of type " + attrType.getName();
+ if (exp instanceof PropertyExpression) {
+ addError(base + " not a property expression", exp);
+ } else if (exp instanceof VariableExpression && ((VariableExpression)exp).getAccessedVariable() instanceof FieldNode) {
+ addError(base + " not a field expression", exp);
+ } else {
+ addError(base, exp);
+ }
+ return ConstantExpression.EMPTY_EXPRESSION;
+ }
+
+ /**
+ * @param attrName the name
+ * @param expression the expression
+ * @param attrType the type
+ */
+ protected void visitAnnotationExpression(String attrName, AnnotationConstantExpression expression, ClassNode attrType) {
+ AnnotationNode annotationNode = (AnnotationNode) expression.getValue();
+ AnnotationVisitor visitor = new AnnotationVisitor(this.source, this.errorCollector);
+ // TODO track Deprecated usage and give a warning?
+ visitor.visit(annotationNode);
+ }
+
+ protected void visitListExpression(String attrName, ListExpression listExpr, ClassNode elementType) {
+ for (Expression expression : listExpr.getExpressions()) {
+ visitExpression(attrName, expression, elementType);
+ }
+ }
+
+ protected void visitConstantExpression(String attrName, ConstantExpression constExpr, ClassNode attrType) {
+ ClassNode constType = constExpr.getType();
+ ClassNode wrapperType = ClassHelper.getWrapper(constType);
+ if (!hasCompatibleType(attrType, wrapperType)) {
+ addError("Attribute '" + attrName + "' should have type '" + attrType.getName()
+ + "'; but found type '" + constType.getName() + "'", constExpr);
+ }
+ }
+
+ private static boolean hasCompatibleType(ClassNode attrType, ClassNode wrapperType) {
+ return wrapperType.isDerivedFrom(ClassHelper.getWrapper(attrType));
+ }
+
+ protected void visitEnumExpression(String attrName, PropertyExpression propExpr, ClassNode attrType) {
+ if (!propExpr.getObjectExpression().getType().isDerivedFrom(attrType)) {
+ addError("Attribute '" + attrName + "' should have type '" + attrType.getName() + "' (Enum), but found "
+ + propExpr.getObjectExpression().getType().getName(),
+ propExpr);
+ }
+ }
+
+ protected void addError(String msg) {
+ addError(msg, this.annotation);
+ }
+
+ protected void addError(String msg, ASTNode expr) {
+ this.errorCollector.addErrorAndContinue(
+ new SyntaxErrorMessage(new SyntaxException(msg + " in @" + this.reportClass.getName() + '\n', expr.getLineNumber(), expr.getColumnNumber(), expr.getLastLineNumber(), expr.getLastColumnNumber()), this.source)
+ );
+ }
+
+ public void checkCircularReference(ClassNode searchClass, ClassNode attrType, Expression startExp) {
+ if (!isValidAnnotationClass(attrType)) return;
+ if (!(startExp instanceof AnnotationConstantExpression)) {
+ addError("Found '" + startExp.getText() + "' when expecting an Annotation Constant", startExp);
+ return;
+ }
+ AnnotationConstantExpression ace = (AnnotationConstantExpression) startExp;
+ AnnotationNode annotationNode = (AnnotationNode) ace.getValue();
+ if (annotationNode.getClassNode().equals(searchClass)) {
+ addError("Circular reference discovered in " + searchClass.getName(), startExp);
+ return;
+ }
+ ClassNode cn = annotationNode.getClassNode();
+ for (MethodNode method : cn.getMethods()) {
+ if (method.getReturnType().equals(searchClass)) {
+ addError("Circular reference discovered in " + cn.getName(), startExp);
+ }
+ ReturnStatement code = (ReturnStatement) method.getCode();
+ if (code == null) continue;
+ checkCircularReference(searchClass, method.getReturnType(), code.getExpression());
+ }
+ }
+
+}
diff --git a/src/main/java/org/codehaus/groovy/classgen/BytecodeSequence.java b/src/main/java/org/codehaus/groovy/classgen/BytecodeSequence.java
index c5a6645..7da3c4d 100644
--- a/src/main/java/org/codehaus/groovy/classgen/BytecodeSequence.java
+++ b/src/main/java/org/codehaus/groovy/classgen/BytecodeSequence.java
@@ -1,81 +1,81 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.codehaus.groovy.classgen;
-
-import org.codehaus.groovy.ast.ASTNode;
-import org.codehaus.groovy.ast.GroovyCodeVisitor;
-import org.codehaus.groovy.ast.stmt.Statement;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * This class represents a sequence of BytecodeInstructions
- * or ASTNodes. The evaluation is depending on the type of
- * the visitor.
- *
- * @see BytecodeInstruction
- * @see ASTNode
- */
-
-public class BytecodeSequence extends Statement {
- private final List<BytecodeInstruction> instructions;
-
- public BytecodeSequence(List instructions) {
- this.instructions = instructions;
- }
-
- public BytecodeSequence(BytecodeInstruction instruction) {
- this.instructions = new ArrayList(1);
- this.instructions.add(instruction);
- }
-
- /**
- * Delegates to the visit method used for this class.
- * If the visitor is a ClassGenerator, then
- * {@link ClassGenerator#visitBytecodeSequence(BytecodeSequence)}
- * is called with this instance. If the visitor is no
- * ClassGenerator, then this method will call visit on
- * each ASTNode element sorted by this class. If one
- * element is a BytecodeInstruction, then it will be skipped
- * as it is no ASTNode.
- *
- * @param visitor the visitor
- * @see ClassGenerator
- */
- public void visit(GroovyCodeVisitor visitor) {
- if (visitor instanceof ClassGenerator) {
- ClassGenerator gen = (ClassGenerator) visitor;
- gen.visitBytecodeSequence(this);
- return;
- }
- for (Iterator iterator = instructions.iterator(); iterator.hasNext();) {
- Object part = (Object) iterator.next();
- if (part instanceof ASTNode) {
- ((ASTNode)part).visit(visitor);
- }
- }
- }
-
- public List getInstructions() {
- return instructions;
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.codehaus.groovy.classgen;
+
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.stmt.Statement;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * This class represents a sequence of BytecodeInstructions
+ * or ASTNodes. The evaluation is depending on the type of
+ * the visitor.
+ *
+ * @see BytecodeInstruction
+ * @see ASTNode
+ */
+
+public class BytecodeSequence extends Statement {
+ private final List<BytecodeInstruction> instructions;
+
+ public BytecodeSequence(List instructions) {
+ this.instructions = instructions;
+ }
+
+ public BytecodeSequence(BytecodeInstruction instruction) {
+ this.instructions = new ArrayList(1);
+ this.instructions.add(instruction);
+ }
+
+ /**
+ * Delegates to the visit method used for this class.
+ * If the visitor is a ClassGenerator, then
+ * {@link ClassGenerator#visitBytecodeSequence(BytecodeSequence)}
+ * is called with this instance. If the visitor is no
+ * ClassGenerator, then this method will call visit on
+ * each ASTNode element sorted by this class. If one
+ * element is a BytecodeInstruction, then it will be skipped
+ * as it is no ASTNode.
+ *
+ * @param visitor the visitor
+ * @see ClassGenerator
+ */
+ public void visit(GroovyCodeVisitor visitor) {
+ if (visitor instanceof ClassGenerator) {
+ ClassGenerator gen = (ClassGenerator) visitor;
+ gen.visitBytecodeSequence(this);
+ return;
+ }
+ for (Iterator iterator = instructions.iterator(); iterator.hasNext();) {
+ Object part = (Object) iterator.next();
+ if (part instanceof ASTNode) {
+ ((ASTNode)part).visit(visitor);
+ }
+ }
+ }
+
+ public List getInstructions() {
+ return instructions;
+ }
+
+}
diff --git a/src/main/java/org/codehaus/groovy/classgen/ExtendedVerifier.java b/src/main/java/org/codehaus/groovy/classgen/ExtendedVerifier.java
index 8b7ed89..96849ac 100644
--- a/src/main/java/org/codehaus/groovy/classgen/ExtendedVerifier.java
+++ b/src/main/java/org/codehaus/groovy/classgen/ExtendedVerifier.java
@@ -1,341 +1,341 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.codehaus.groovy.classgen;
-
-import org.codehaus.groovy.ast.ASTNode;
-import org.codehaus.groovy.ast.AnnotatedNode;
-import org.codehaus.groovy.ast.AnnotationNode;
-import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
-import org.codehaus.groovy.ast.ClassHelper;
-import org.codehaus.groovy.ast.ClassNode;
-import org.codehaus.groovy.ast.ConstructorNode;
-import org.codehaus.groovy.ast.FieldNode;
-import org.codehaus.groovy.ast.GenericsType;
-import org.codehaus.groovy.ast.MethodNode;
-import org.codehaus.groovy.ast.PackageNode;
-import org.codehaus.groovy.ast.Parameter;
-import org.codehaus.groovy.ast.PropertyNode;
-import org.codehaus.groovy.ast.expr.AnnotationConstantExpression;
-import org.codehaus.groovy.ast.expr.ClassExpression;
-import org.codehaus.groovy.ast.expr.DeclarationExpression;
-import org.codehaus.groovy.ast.expr.Expression;
-import org.codehaus.groovy.ast.expr.ListExpression;
-import org.codehaus.groovy.ast.stmt.ReturnStatement;
-import org.codehaus.groovy.ast.stmt.Statement;
-import org.codehaus.groovy.ast.tools.ParameterUtils;
-import org.codehaus.groovy.control.AnnotationConstantsVisitor;
-import org.codehaus.groovy.control.CompilerConfiguration;
-import org.codehaus.groovy.control.ErrorCollector;
-import org.codehaus.groovy.control.SourceUnit;
-import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
-import org.codehaus.groovy.syntax.SyntaxException;
-import org.objectweb.asm.Opcodes;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-import static org.codehaus.groovy.ast.tools.GenericsUtils.correctToGenericsSpec;
-import static org.codehaus.groovy.ast.tools.GenericsUtils.correctToGenericsSpecRecurse;
-import static org.codehaus.groovy.ast.tools.GenericsUtils.createGenericsSpec;
-
-/**
- * A specialized Groovy AST visitor meant to perform additional verifications upon the
- * current AST. Currently it does checks on annotated nodes and annotations itself.
- * <p>
- * Current limitations:
- * - annotations on local variables are not supported
- */
-public class ExtendedVerifier extends ClassCodeVisitorSupport {
- public static final String JVM_ERROR_MESSAGE = "Please make sure you are running on a JVM >= 1.5";
-
- private final SourceUnit source;
- private ClassNode currentClass;
-
- public ExtendedVerifier(SourceUnit sourceUnit) {
- this.source = sourceUnit;
- }
-
- public void visitClass(ClassNode node) {
- AnnotationConstantsVisitor acv = new AnnotationConstantsVisitor();
- acv.visitClass(node, this.source);
- this.currentClass = node;
- if (node.isAnnotationDefinition()) {
- visitAnnotations(node, AnnotationNode.ANNOTATION_TARGET);
- } else {
- visitAnnotations(node, AnnotationNode.TYPE_TARGET);
- }
- PackageNode packageNode = node.getPackage();
- if (packageNode != null) {
- visitAnnotations(packageNode, AnnotationNode.PACKAGE_TARGET);
- }
- node.visitContents(this);
- }
-
- public void visitField(FieldNode node) {
- visitAnnotations(node, AnnotationNode.FIELD_TARGET);
- }
-
- @Override
- public void visitDeclarationExpression(DeclarationExpression expression) {
- visitAnnotations(expression, AnnotationNode.LOCAL_VARIABLE_TARGET);
- }
-
- public void visitConstructor(ConstructorNode node) {
- visitConstructorOrMethod(node, AnnotationNode.CONSTRUCTOR_TARGET);
- }
-
- public void visitMethod(MethodNode node) {
- visitConstructorOrMethod(node, AnnotationNode.METHOD_TARGET);
- }
-
- private void visitConstructorOrMethod(MethodNode node, int methodTarget) {
- visitAnnotations(node, methodTarget);
- for (int i = 0; i < node.getParameters().length; i++) {
- Parameter parameter = node.getParameters()[i];
- visitAnnotations(parameter, AnnotationNode.PARAMETER_TARGET);
- }
-
- if (this.currentClass.isAnnotationDefinition() && !node.isStaticConstructor()) {
- ErrorCollector errorCollector = new ErrorCollector(this.source.getConfiguration());
- AnnotationVisitor visitor = new AnnotationVisitor(this.source, errorCollector);
- visitor.setReportClass(currentClass);
- visitor.checkReturnType(node.getReturnType(), node);
- if (node.getParameters().length > 0) {
- addError("Annotation members may not have parameters.", node.getParameters()[0]);
- }
- if (node.getExceptions().length > 0) {
- addError("Annotation members may not have a throws clause.", node.getExceptions()[0]);
- }
- ReturnStatement code = (ReturnStatement) node.getCode();
- if (code != null) {
- visitor.visitExpression(node.getName(), code.getExpression(), node.getReturnType());
- visitor.checkCircularReference(currentClass, node.getReturnType(), code.getExpression());
- }
- this.source.getErrorCollector().addCollectorContents(errorCollector);
- }
- Statement code = node.getCode();
- if (code != null) {
- code.visit(this);
- }
-
- }
-
- public void visitProperty(PropertyNode node) {
- }
-
- protected void visitAnnotations(AnnotatedNode node, int target) {
- if (node.getAnnotations().isEmpty()) {
- return;
- }
- this.currentClass.setAnnotated(true);
- if (!isAnnotationCompatible()) {
- addError("Annotations are not supported in the current runtime. " + JVM_ERROR_MESSAGE, node);
- return;
- }
- Map<String, List<AnnotationNode>> runtimeAnnotations = new LinkedHashMap<String, List<AnnotationNode>>();
- for (AnnotationNode unvisited : node.getAnnotations()) {
- AnnotationNode visited = visitAnnotation(unvisited);
- String name = visited.getClassNode().getName();
- if (visited.hasRuntimeRetention()) {
- List<AnnotationNode> seen = runtimeAnnotations.get(name);
- if (seen == null) {
- seen = new ArrayList<AnnotationNode>();
- }
- seen.add(visited);
- runtimeAnnotations.put(name, seen);
- }
- boolean isTargetAnnotation = name.equals("java.lang.annotation.Target");
-
- // Check if the annotation target is correct, unless it's the target annotating an annotation definition
- // defining on which target elements the annotation applies
- if (!isTargetAnnotation && !visited.isTargetAllowed(target)) {
- addError("Annotation @" + name + " is not allowed on element "
- + AnnotationNode.targetToName(target), visited);
- }
- visitDeprecation(node, visited);
- visitOverride(node, visited);
- }
- checkForDuplicateAnnotations(node, runtimeAnnotations);
- }
-
- private void checkForDuplicateAnnotations(AnnotatedNode node, Map<String, List<AnnotationNode>> runtimeAnnotations) {
- for (Map.Entry<String, List<AnnotationNode>> next : runtimeAnnotations.entrySet()) {
- if (next.getValue().size() > 1) {
- ClassNode repeatable = null;
- AnnotationNode repeatee = next.getValue().get(0);
- List<AnnotationNode> repeateeAnnotations = repeatee.getClassNode().getAnnotations();
- for (AnnotationNode anno : repeateeAnnotations) {
- ClassNode annoClassNode = anno.getClassNode();
- if (annoClassNode.getName().equals("java.lang.annotation.Repeatable")) {
- Expression value = anno.getMember("value");
- if (value instanceof ClassExpression) {
- ClassExpression ce = (ClassExpression) value;
- if (ce.getType() != null && ce.getType().isAnnotationDefinition()) {
- repeatable = ce.getType();
- break;
- }
- }
- }
- }
- if (repeatable != null) {
- AnnotationNode collector = new AnnotationNode(repeatable);
- collector.setRuntimeRetention(true); // checked earlier
- List<Expression> annos = new ArrayList<Expression>();
- for (AnnotationNode an : next.getValue()) {
- annos.add(new AnnotationConstantExpression(an));
- }
- collector.addMember("value", new ListExpression(annos));
- node.addAnnotation(collector);
- node.getAnnotations().removeAll(next.getValue());
- }
- }
- }
- }
-
- private static void visitDeprecation(AnnotatedNode node, AnnotationNode visited) {
- if (visited.getClassNode().isResolved() && visited.getClassNode().getName().equals("java.lang.Deprecated")) {
- if (node instanceof MethodNode) {
- MethodNode mn = (MethodNode) node;
- mn.setModifiers(mn.getModifiers() | Opcodes.ACC_DEPRECATED);
- } else if (node instanceof FieldNode) {
- FieldNode fn = (FieldNode) node;
- fn.setModifiers(fn.getModifiers() | Opcodes.ACC_DEPRECATED);
- } else if (node instanceof ClassNode) {
- ClassNode cn = (ClassNode) node;
- cn.setModifiers(cn.getModifiers() | Opcodes.ACC_DEPRECATED);
- }
- }
- }
-
- // TODO GROOVY-5011 handle case of @Override on a property
- private void visitOverride(AnnotatedNode node, AnnotationNode visited) {
- ClassNode annotationClassNode = visited.getClassNode();
- if (annotationClassNode.isResolved() && annotationClassNode.getName().equals("java.lang.Override")) {
- if (node instanceof MethodNode && !Boolean.TRUE.equals(node.getNodeMetaData(Verifier.DEFAULT_PARAMETER_GENERATED))) {
- boolean override = false;
- MethodNode origMethod = (MethodNode) node;
- ClassNode cNode = origMethod.getDeclaringClass();
- if (origMethod.hasDefaultValue()) {
- List<MethodNode> variants = cNode.getDeclaredMethods(origMethod.getName());
- for (MethodNode m : variants) {
- if (m.getAnnotations().contains(visited) && isOverrideMethod(m)) {
- override = true;
- break;
- }
- }
- } else {
- override = isOverrideMethod(origMethod);
- }
-
- if (!override) {
- addError("Method '" + origMethod.getName() + "' from class '" + cNode.getName() + "' does not override " +
- "method from its superclass or interfaces but is annotated with @Override.", visited);
- }
- }
- }
- }
-
- private static boolean isOverrideMethod(MethodNode method) {
- ClassNode cNode = method.getDeclaringClass();
- ClassNode next = cNode;
- outer:
- while (next != null) {
- Map genericsSpec = createGenericsSpec(next);
- MethodNode mn = correctToGenericsSpec(genericsSpec, method);
- if (next != cNode) {
- ClassNode correctedNext = correctToGenericsSpecRecurse(genericsSpec, next);
- MethodNode found = getDeclaredMethodCorrected(genericsSpec, mn, correctedNext);
- if (found != null) break;
- }
- List<ClassNode> ifaces = new ArrayList<ClassNode>(Arrays.asList(next.getInterfaces()));
- Map updatedGenericsSpec = new HashMap(genericsSpec);
- while (!ifaces.isEmpty()) {
- ClassNode origInterface = ifaces.remove(0);
- if (!origInterface.equals(ClassHelper.OBJECT_TYPE)) {
- updatedGenericsSpec = createGenericsSpec(origInterface, updatedGenericsSpec);
- ClassNode iNode = correctToGenericsSpecRecurse(updatedGenericsSpec, origInterface);
- MethodNode found2 = getDeclaredMethodCorrected(updatedGenericsSpec, mn, iNode);
- if (found2 != null) break outer;
- ifaces.addAll(Arrays.asList(iNode.getInterfaces()));
- }
- }
- ClassNode superClass = next.getUnresolvedSuperClass();
- if (superClass != null) {
- next = correctToGenericsSpecRecurse(updatedGenericsSpec, superClass);
- } else {
- next = null;
- }
- }
- return next != null;
- }
-
- private static MethodNode getDeclaredMethodCorrected(Map genericsSpec, MethodNode mn, ClassNode correctedNext) {
- for (MethodNode orig : correctedNext.getDeclaredMethods(mn.getName())) {
- MethodNode method = correctToGenericsSpec(genericsSpec, orig);
- if (ParameterUtils.parametersEqual(method.getParameters(), mn.getParameters())) {
- return method;
- }
- }
- return null;
- }
-
- /**
- * Resolve metadata and details of the annotation.
- *
- * @param unvisited the node to visit
- * @return the visited node
- */
- private AnnotationNode visitAnnotation(AnnotationNode unvisited) {
- ErrorCollector errorCollector = new ErrorCollector(this.source.getConfiguration());
- AnnotationVisitor visitor = new AnnotationVisitor(this.source, errorCollector);
- AnnotationNode visited = visitor.visit(unvisited);
- this.source.getErrorCollector().addCollectorContents(errorCollector);
- return visited;
- }
-
- /**
- * Check if the current runtime allows Annotation usage.
- *
- * @return true if running on a 1.5+ runtime
- */
- protected boolean isAnnotationCompatible() {
- return CompilerConfiguration.isPostJDK5(this.source.getConfiguration().getTargetBytecode());
- }
-
- public void addError(String msg, ASTNode expr) {
- this.source.getErrorCollector().addErrorAndContinue(
- new SyntaxErrorMessage(
- new SyntaxException(msg + '\n', expr.getLineNumber(), expr.getColumnNumber(), expr.getLastLineNumber(), expr.getLastColumnNumber()), this.source)
- );
- }
-
- @Override
- protected SourceUnit getSourceUnit() {
- return source;
- }
-
- // TODO use it or lose it
- public void visitGenericType(GenericsType genericsType) {
-
- }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.codehaus.groovy.classgen;
+
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.AnnotatedNode;
+import org.codehaus.groovy.ast.AnnotationNode;
+import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.ConstructorNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.GenericsType;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.PackageNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.PropertyNode;
+import org.codehaus.groovy.ast.expr.AnnotationConstantExpression;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.DeclarationExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.ListExpression;
+import org.codehaus.groovy.ast.stmt.ReturnStatement;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.ast.tools.ParameterUtils;
+import org.codehaus.groovy.control.AnnotationConstantsVisitor;
+import org.codehaus.groovy.control.CompilerConfiguration;
+import org.codehaus.groovy.control.ErrorCollector;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
+import org.codehaus.groovy.syntax.SyntaxException;
+import org.objectweb.asm.Opcodes;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.codehaus.groovy.ast.tools.GenericsUtils.correctToGenericsSpec;
+import static org.codehaus.groovy.ast.tools.GenericsUtils.correctToGenericsSpecRecurse;
+import static org.codehaus.groovy.ast.tools.GenericsUtils.createGenericsSpec;
+
+/**
+ * A specialized Groovy AST visitor meant to perform additional verifications upon the
+ * current AST. Currently it does checks on annotated nodes and annotations itself.
+ * <p>
+ * Current limitations:
+ * - annotations on local variables are not supported
+ */
+public class ExtendedVerifier extends ClassCodeVisitorSupport {
+ public static final String JVM_ERROR_MESSAGE = "Please make sure you are running on a JVM >= 1.5";
+
+ private final SourceUnit source;
+ private ClassNode currentClass;
+
+ public ExtendedVerifier(SourceUnit sourceUnit) {
+ this.source = sourceUnit;
+ }
+
+ public void visitClass(ClassNode node) {
+ AnnotationConstantsVisitor acv = new AnnotationConstantsVisitor();
+ acv.visitClass(node, this.source);
+ this.currentClass = node;
+ if (node.isAnnotationDefinition()) {
+ visitAnnotations(node, AnnotationNode.ANNOTATION_TARGET);
+ } else {
+ visitAnnotations(node, AnnotationNode.TYPE_TARGET);
+ }
+ PackageNode packageNode = node.getPackage();
+ if (packageNode != null) {
+ visitAnnotations(packageNode, AnnotationNode.PACKAGE_TARGET);
+ }
+ node.visitContents(this);
+ }
+
+ public void visitField(FieldNode node) {
+ visitAnnotations(node, AnnotationNode.FIELD_TARGET);
+ }
+
+ @Override
+ public void visitDeclarationExpression(DeclarationExpression expression) {
+ visitAnnotations(expression, AnnotationNode.LOCAL_VARIABLE_TARGET);
+ }
+
+ public void visitConstructor(ConstructorNode node) {
+ visitConstructorOrMethod(node, AnnotationNode.CONSTRUCTOR_TARGET);
+ }
+
+ public void visitMethod(MethodNode node) {
+ visitConstructorOrMethod(node, AnnotationNode.METHOD_TARGET);
+ }
+
+ private void visitConstructorOrMethod(MethodNode node, int methodTarget) {
+ visitAnnotations(node, methodTarget);
+ for (int i = 0; i < node.getParameters().length; i++) {
+ Parameter parameter = node.getParameters()[i];
+ visitAnnotations(parameter, AnnotationNode.PARAMETER_TARGET);
+ }
+
+ if (this.currentClass.isAnnotationDefinition() && !node.isStaticConstructor()) {
+ ErrorCollector errorCollector = new ErrorCollector(this.source.getConfiguration());
+ AnnotationVisitor visitor = new AnnotationVisitor(this.source, errorCollector);
+ visitor.setReportClass(currentClass);
+ visitor.checkReturnType(node.getReturnType(), node);
+ if (node.getParameters().length > 0) {
+ addError("Annotation members may not have parameters.", node.getParameters()[0]);
+ }
+ if (node.getExceptions().length > 0) {
+ addError("Annotation members may not have a throws clause.", node.getExceptions()[0]);
+ }
+ ReturnStatement code = (ReturnStatement) node.getCode();
+ if (code != null) {
+ visitor.visitExpression(node.getName(), code.getExpression(), node.getReturnType());
+ visitor.checkCircularReference(currentClass, node.getReturnType(), code.getExpression());
+ }
+ this.source.getErrorCollector().addCollectorContents(errorCollector);
+ }
+ Statement code = node.getCode();
+ if (code != null) {
+ code.visit(this);
+ }
+
+ }
+
+ public void visitProperty(PropertyNode node) {
+ }
+
+ protected void visitAnnotations(AnnotatedNode node, int target) {
+ if (node.getAnnotations().isEmpty()) {
+ return;
+ }
+ this.currentClass.setAnnotated(true);
+ if (!isAnnotationCompatible()) {
+ addError("Annotations are not supported in the current runtime. " + JVM_ERROR_MESSAGE, node);
+ return;
+ }
+ Map<String, List<AnnotationNode>> runtimeAnnotations = new LinkedHashMap<String, List<AnnotationNode>>();
+ for (AnnotationNode unvisited : node.getAnnotations()) {
+ AnnotationNode visited = visitAnnotation(unvisited);
+ String name = visited.getClassNode().getName();
+ if (visited.hasRuntimeRetention()) {
+ List<AnnotationNode> seen = runtimeAnnotations.get(name);
+ if (seen == null) {
+ seen = new ArrayList<AnnotationNode>();
+ }
+ seen.add(visited);
+ runtimeAnnotations.put(name, seen);
+ }
+ boolean isTargetAnnotation = name.equals("java.lang.annotation.Target");
+
+ // Check if the annotation target is correct, unless it's the target annotating an annotation definition
+ // defining on which target elements the annotation applies
+ if (!isTargetAnnotation && !visited.isTargetAllowed(target)) {
+ addError("Annotation @" + name + " is not allowed on element "
+ + AnnotationNode.targetToName(target), visited);
+ }
+ visitDeprecation(node, visited);
+ visitOverride(node, visited);
+ }
+ checkForDuplicateAnnotations(node, runtimeAnnotations);
+ }
+
+ private void checkForDuplicateAnnotations(AnnotatedNode node, Map<String, List<AnnotationNode>> runtimeAnnotations) {
+ for (Map.Entry<String, List<AnnotationNode>> next : runtimeAnnotations.entrySet()) {
+ if (next.getValue().size() > 1) {
+ ClassNode repeatable = null;
+ AnnotationNode repeatee = next.getValue().get(0);
+ List<AnnotationNode> repeateeAnnotations = repeatee.getClassNode().getAnnotations();
+ for (AnnotationNode anno : repeateeAnnotations) {
+ ClassNode annoClassNode = anno.getClassNode();
+ if (annoClassNode.getName().equals("java.lang.annotation.Repeatable")) {
+ Expression value = anno.getMember("value");
+ if (value instanceof ClassExpression) {
+ ClassExpression ce = (ClassExpression) value;
+ if (ce.getType() != null && ce.getType().isAnnotationDefinition()) {
+ repeatable = ce.getType();
+ break;
+ }
+ }
+ }
+ }
+ if (repeatable != null) {
+ AnnotationNode collector = new AnnotationNode(repeatable);
+ collector.setRuntimeRetention(true); // checked earlier
+ List<Expression> annos = new ArrayList<Expression>();
+ for (AnnotationNode an : next.getValue()) {
+ annos.add(new AnnotationConstantExpression(an));
+ }
+ collector.addMember("value", new ListExpression(annos));
+ node.addAnnotation(collector);
+ node.getAnnotations().removeAll(next.getValue());
+ }
+ }
+ }
+ }
+
+ private static void visitDeprecation(AnnotatedNode node, AnnotationNode visited) {
+ if (visited.getClassNode().isResolved() && visited.getClassNode().getName().equals("java.lang.Deprecated")) {
+ if (node instanceof MethodNode) {
+ MethodNode mn = (MethodNode) node;
+ mn.setModifiers(mn.getModifiers() | Opcodes.ACC_DEPRECATED);
+ } else if (node instanceof FieldNode) {
+ FieldNode fn = (FieldNode) node;
+ fn.setModifiers(fn.getModifiers() | Opcodes.ACC_DEPRECATED);
+ } else if (node instanceof ClassNode) {
+ ClassNode cn = (ClassNode) node;
+ cn.setModifiers(cn.getModifiers() | Opcodes.ACC_DEPRECATED);
+ }
+ }
+ }
+
+ // TODO GROOVY-5011 handle case of @Override on a property
+ private void visitOverride(AnnotatedNode node, AnnotationNode visited) {
+ ClassNode annotationClassNode = visited.getClassNode();
+ if (annotationClassNode.isResolved() && annotationClassNode.getName().equals("java.lang.Override")) {
+ if (node instanceof MethodNode && !Boolean.TRUE.equals(node.getNodeMetaData(Verifier.DEFAULT_PARAMETER_GENERATED))) {
+ boolean override = false;
+ MethodNode origMethod = (MethodNode) node;
+ ClassNode cNode = origMethod.getDeclaringClass();
+ if (origMethod.hasDefaultValue()) {
+ List<MethodNode> variants = cNode.getDeclaredMethods(origMethod.getName());
+ for (MethodNode m : variants) {
+ if (m.getAnnotations().contains(visited) && isOverrideMethod(m)) {
+ override = true;
+ break;
+ }
+ }
+ } else {
+ override = isOverrideMethod(origMethod);
+ }
+
+ if (!override) {
+ addError("Method '" + origMethod.getName() + "' from class '" + cNode.getName() + "' does not override " +
+ "method from its superclass or interfaces but is annotated with @Override.", visited);
+ }
+ }
+ }
+ }
+
+ private static boolean isOverrideMethod(MethodNode method) {
+ ClassNode cNode = method.getDeclaringClass();
+ ClassNode next = cNode;
+ outer:
+ while (next != null) {
+ Map genericsSpec = createGenericsSpec(next);
+ MethodNode mn = correctToGenericsSpec(genericsSpec, method);
+ if (next != cNode) {
+ ClassNode correctedNext = correctToGenericsSpecRecurse(genericsSpec, next);
+ MethodNode found = getDeclaredMethodCorrected(genericsSpec, mn, correctedNext);
+ if (found != null) break;
+ }
+ List<ClassNode> ifaces = new ArrayList<ClassNode>(Arrays.asList(next.getInterfaces()));
+ Map updatedGenericsSpec = new HashMap(genericsSpec);
+ while (!ifaces.isEmpty()) {
+ ClassNode origInterface = ifaces.remove(0);
+ if (!origInterface.equals(ClassHelper.OBJECT_TYPE)) {
+ updatedGenericsSpec = createGenericsSpec(origInterface, updatedGenericsSpec);
+ ClassNode iNode = correctToGenericsSpecRecurse(updatedGenericsSpec, origInterface);
+ MethodNode found2 = getDeclaredMethodCorrected(updatedGenericsSpec, mn, iNode);
+ if (found2 != null) break outer;
+ ifaces.addAll(Arrays.asList(iNode.getInterfaces()));
+ }
+ }
+ ClassNode superClass = next.getUnresolvedSuperClass();
+ if (superClass != null) {
+ next = correctToGenericsSpecRecurse(updatedGenericsSpec, superClass);
+ } else {
+ next = null;
+ }
+ }
+ return next != null;
+ }
+
+ private static MethodNode getDeclaredMethodCorrected(Map genericsSpec, MethodNode mn, ClassNode correctedNext) {
+ for (MethodNode orig : correctedNext.getDeclaredMethods(mn.getName())) {
+ MethodNode method = correctToGenericsSpec(genericsSpec, orig);
+ if (ParameterUtils.parametersEqual(method.getParameters(), mn.getParameters())) {
+ return method;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Resolve metadata and details of the annotation.
+ *
+ * @param unvisited the node to visit
+ * @return the visited node
+ */
+ private AnnotationNode visitAnnotation(AnnotationNode unvisited) {
+ ErrorCollector errorCollector = new ErrorCollector(this.source.getConfiguration());
+ AnnotationVisitor visitor = new AnnotationVisitor(this.source, errorCollector);
+ AnnotationNode visited = visitor.visit(unvisited);
+ this.source.getErrorCollector().addCollectorContents(errorCollector);
+ return visited;
+ }
+
+ /**
+ * Check if the current runtime allows Annotation usage.
+ *
+ * @return true if running on a 1.5+ runtime
+ */
+ protected boolean isAnnotationCompatible() {
+ return CompilerConfiguration.isPostJDK5(this.source.getConfiguration().getTargetBytecode());
+ }
+
+ public void addError(String msg, ASTNode expr) {
+ this.source.getErrorCollector().addErrorAndContinue(
+ new SyntaxErrorMessage(
+ new SyntaxException(msg + '\n', expr.getLineNumber(), expr.getColumnNumber(), expr.getLastLineNumber(), expr.getLastColumnNumber()), this.source)
+ );
+ }
+
+ @Override
+ protected SourceUnit getSourceUnit() {
+ return source;
+ }
+
+ // TODO use it or lose it
+ public void visitGenericType(GenericsType genericsType) {
+
+ }
+}
diff --git a/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitorHelper.java b/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitorHelper.java
index 0971146..9452768 100644
--- a/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitorHelper.java
+++ b/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitorHelper.java
@@ -1,143 +1,143 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.codehaus.groovy.classgen;
-
-import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
-import org.codehaus.groovy.ast.ClassHelper;
-import org.codehaus.groovy.ast.ClassNode;
-import org.codehaus.groovy.ast.FieldNode;
-import org.codehaus.groovy.ast.InnerClassNode;
-import org.codehaus.groovy.ast.Parameter;
-import org.codehaus.groovy.ast.VariableScope;
-import org.codehaus.groovy.ast.expr.ArgumentListExpression;
-import org.codehaus.groovy.ast.expr.BinaryExpression;
-import org.codehaus.groovy.ast.expr.ConstantExpression;
-import org.codehaus.groovy.ast.expr.Expression;
-import org.codehaus.groovy.ast.expr.FieldExpression;
-import org.codehaus.groovy.ast.expr.GStringExpression;
-import org.codehaus.groovy.ast.expr.MethodCallExpression;
-import org.codehaus.groovy.ast.expr.PropertyExpression;
-import org.codehaus.groovy.ast.expr.SpreadExpression;
-import org.codehaus.groovy.ast.expr.VariableExpression;
-import org.codehaus.groovy.ast.stmt.BlockStatement;
-import org.codehaus.groovy.ast.stmt.ExpressionStatement;
-import org.codehaus.groovy.ast.stmt.ReturnStatement;
-import org.codehaus.groovy.syntax.Token;
-import org.codehaus.groovy.syntax.Types;
-import org.objectweb.asm.Opcodes;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public abstract class InnerClassVisitorHelper extends ClassCodeVisitorSupport {
- protected static void setPropertyGetterDispatcher(BlockStatement block, Expression thiz, Parameter[] parameters) {
- List<ConstantExpression> gStringStrings = new ArrayList<ConstantExpression>();
- gStringStrings.add(new ConstantExpression(""));
- gStringStrings.add(new ConstantExpression(""));
- List<Expression> gStringValues = new ArrayList<Expression>();
- gStringValues.add(new VariableExpression(parameters[0]));
- block.addStatement(
- new ReturnStatement(
- new PropertyExpression(
- thiz,
- new GStringExpression("$name", gStringStrings, gStringValues)
- )
- )
- );
- }
-
- protected static void setPropertySetterDispatcher(BlockStatement block, Expression thiz, Parameter[] parameters) {
- List<ConstantExpression> gStringStrings = new ArrayList<ConstantExpression>();
- gStringStrings.add(new ConstantExpression(""));
- gStringStrings.add(new ConstantExpression(""));
- List<Expression> gStringValues = new ArrayList<Expression>();
- gStringValues.add(new VariableExpression(parameters[0]));
- block.addStatement(
- new ExpressionStatement(
- new BinaryExpression(
- new PropertyExpression(
- thiz,
- new GStringExpression("$name", gStringStrings, gStringValues)
- ),
- Token.newSymbol(Types.ASSIGN, -1, -1),
- new VariableExpression(parameters[1])
- )
- )
- );
- }
-
- protected static void setMethodDispatcherCode(BlockStatement block, Expression thiz, Parameter[] parameters) {
- List<ConstantExpression> gStringStrings = new ArrayList<ConstantExpression>();
- gStringStrings.add(new ConstantExpression(""));
- gStringStrings.add(new ConstantExpression(""));
- List<Expression> gStringValues = new ArrayList<Expression>();
- gStringValues.add(new VariableExpression(parameters[0]));
- block.addStatement(
- new ReturnStatement(
- new MethodCallExpression(
- thiz,
- new GStringExpression("$name", gStringStrings, gStringValues),
- new ArgumentListExpression(
- new SpreadExpression(new VariableExpression(parameters[1]))
- )
- )
- )
- );
- }
-
- protected static boolean isStatic(InnerClassNode node) {
- VariableScope scope = node.getVariableScope();
- if (scope != null) return scope.getParent().isInStaticContext();
- return (node.getModifiers() & Opcodes.ACC_STATIC) != 0;
- }
-
- protected static ClassNode getClassNode(ClassNode node, boolean isStatic) {
- if (isStatic) node = ClassHelper.CLASS_Type;
- return node;
- }
-
- protected static int getObjectDistance(ClassNode node) {
- int count = 0;
- while (node != null && node != ClassHelper.OBJECT_TYPE) {
- count++;
- node = node.getSuperClass();
- }
- return count;
- }
-
- protected static void addFieldInit(Parameter p, FieldNode fn, BlockStatement block) {
- VariableExpression ve = new VariableExpression(p);
- FieldExpression fe = new FieldExpression(fn);
- block.addStatement(new ExpressionStatement(
- new BinaryExpression(fe, Token.newSymbol(Types.ASSIGN, -1, -1), ve)
- ));
- }
-
- protected static boolean shouldHandleImplicitThisForInnerClass(ClassNode cn) {
- if (cn.isEnum() || cn.isInterface()) return false;
- if ((cn.getModifiers() & Opcodes.ACC_STATIC) != 0) return false;
-
- if (!(cn instanceof InnerClassNode)) return false;
- InnerClassNode innerClass = (InnerClassNode) cn;
- // scope != null means aic, we don't handle that here
- if (innerClass.getVariableScope() != null) return false;
- // static inner classes don't need this$0
- return (innerClass.getModifiers() & Opcodes.ACC_STATIC) == 0;
- }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.codehaus.groovy.classgen;
+
+import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.InnerClassNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.VariableScope;
+import org.codehaus.groovy.ast.expr.ArgumentListExpression;
+import org.codehaus.groovy.ast.expr.BinaryExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.FieldExpression;
+import org.codehaus.groovy.ast.expr.GStringExpression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
+import org.codehaus.groovy.ast.expr.SpreadExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.stmt.BlockStatement;
+import org.codehaus.groovy.ast.stmt.ExpressionStatement;
+import org.codehaus.groovy.ast.stmt.ReturnStatement;
+import org.codehaus.groovy.syntax.Token;
+import org.codehaus.groovy.syntax.Types;
+import org.objectweb.asm.Opcodes;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public abstract class InnerClassVisitorHelper extends ClassCodeVisitorSupport {
+ protected static void setPropertyGetterDispatcher(BlockStatement block, Expression thiz, Parameter[] parameters) {
+ List<ConstantExpression> gStringStrings = new ArrayList<ConstantExpression>();
+ gStringStrings.add(new ConstantExpression(""));
+ gStringStrings.add(new ConstantExpression(""));
+ List<Expression> gStringValues = new ArrayList<Expression>();
+ gStringValues.add(new VariableExpression(parameters[0]));
+ block.addStatement(
+ new ReturnStatement(
+ new PropertyExpression(
+ thiz,
+ new GStringExpression("$name", gStringStrings, gStringValues)
+ )
+ )
+ );
+ }
+
+ protected static void setPropertySetterDispatcher(BlockStatement block, Expression thiz, Parameter[] parameters) {
+ List<ConstantExpression> gStringStrings = new ArrayList<ConstantExpression>();
+ gStringStrings.add(new ConstantExpression(""));
+ gStringStrings.add(new ConstantExpression(""));
+ List<Expression> gStringValues = new ArrayList<Expression>();
+ gStringValues.add(new VariableExpression(parameters[0]));
+ block.addStatement(
+ new ExpressionStatement(
+ new BinaryExpression(
+ new PropertyExpression(
+ thiz,
+ new GStringExpression("$name", gStringStrings, gStringValues)
+ ),
+ Token.newSymbol(Types.ASSIGN, -1, -1),
+ new VariableExpression(parameters[1])
+ )
+ )
+ );
+ }
+
+ protected static void setMethodDispatcherCode(BlockStatement block, Expression thiz, Parameter[] parameters) {
+ List<ConstantExpression> gStringStrings = new ArrayList<ConstantExpression>();
+ gStringStrings.add(new ConstantExpression(""));
+ gStringStrings.add(new ConstantExpression(""));
+ List<Expression> gStringValues = new ArrayList<Expression>();
+ gStringValues.add(new VariableExpression(parameters[0]));
+ block.addStatement(
+ new ReturnStatement(
+ new MethodCallExpression(
+ thiz,
+ new GStringExpression("$name", gStringStrings, gStringValues),
+ new ArgumentListExpression(
+ new SpreadExpression(new VariableExpression(parameters[1]))
+ )
+ )
+ )
+ );
+ }
+
+ protected static boolean isStatic(InnerClassNode node) {
+ VariableScope scope = node.getVariableScope();
+ if (scope != null) return scope.getParent().isInStaticContext();
+ return (node.getModifiers() & Opcodes.ACC_STATIC) != 0;
+ }
+
+ protected static ClassNode getClassNode(ClassNode node, boolean isStatic) {
+ if (isStatic) node = ClassHelper.CLASS_Type;
+ return node;
+ }
+
+ protected static int getObjectDistance(ClassNode node) {
+ int count = 0;
+ while (node != null && node != ClassHelper.OBJECT_TYPE) {
+ count++;
+ node = node.getSuperClass();
+ }
+ return count;
+ }
+
+ protected static void addFieldInit(Parameter p, FieldNode fn, BlockStatement block) {
+ VariableExpression ve = new VariableExpression(p);
+ FieldExpression fe = new FieldExpression(fn);
+ block.addStatement(new ExpressionStatement(
+ new BinaryExpression(fe, Token.newSymbol(Types.ASSIGN, -1, -1), ve)
+ ));
+ }
+
+ protected static boolean shouldHandleImplicitThisForInnerClass(ClassNode cn) {
+ if (cn.isEnum() || cn.isInterface()) return false;
+ if ((cn.getModifiers() & Opcodes.ACC_STATIC) != 0) return false;
+
+ if (!(cn instanceof InnerClassNode)) return false;
+ InnerClassNode innerClass = (InnerClassNode) cn;
+ // scope != null means aic, we don't handle that here
+ if (innerClass.getVariableScope() != null) return false;
+ // static inner classes don't need this$0
+ return (innerClass.getModifiers() & Opcodes.ACC_STATIC) == 0;
+ }
+}
diff --git a/src/main/java/org/codehaus/groovy/control/SourceExtensionHandler.java b/src/main/java/org/codehaus/groovy/control/SourceExtensionHandler.java
index 0ca38f5..09d788a 100644
--- a/src/main/java/org/codehaus/groovy/control/SourceExtensionHandler.java
+++ b/src/main/java/org/codehaus/groovy/control/SourceExtensionHandler.java
@@ -1,66 +1,66 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.codehaus.groovy.control;
-
-import groovy.lang.GroovyRuntimeException;
-import org.codehaus.groovy.util.URLStreams;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.net.URL;
-import java.util.Enumeration;
-import java.util.LinkedHashSet;
-import java.util.Set;
-
-/**
- * Looks for source file extensions in META-INF/services/org.codehaus.groovy.source.Extensions
- */
-public class SourceExtensionHandler {
-
- public static Set<String> getRegisteredExtensions(ClassLoader loader) {
- Set<String> extensions = new LinkedHashSet<String>();
- extensions.add("groovy");
- try {
- Enumeration<URL> globalServices = loader.getResources("META-INF/groovy/org.codehaus.groovy.source.Extensions");
- if (!globalServices.hasMoreElements()) {
- globalServices = loader.getResources("META-INF/services/org.codehaus.groovy.source.Extensions");
- }
- while (globalServices.hasMoreElements()) {
- URL service = globalServices.nextElement();
- try (BufferedReader svcIn = new BufferedReader(new InputStreamReader(URLStreams.openUncachedStream(service)))) {
- String extension = svcIn.readLine();
- while (extension != null) {
- extension = extension.trim();
- if (!extension.startsWith("#") && extension.length() > 0) {
- extensions.add(extension);
- }
- extension = svcIn.readLine();
- }
- } catch (IOException ex) {
- throw new GroovyRuntimeException("IO Exception attempting to load registered source extension " +
- service.toExternalForm() + ". Exception: " + ex.toString());
- }
- }
- } catch (IOException ex) {
- throw new GroovyRuntimeException("IO Exception getting registered source extensions. Exception: " + ex.toString());
- }
- return extensions;
- }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.codehaus.groovy.control;
+
+import groovy.lang.GroovyRuntimeException;
+import org.codehaus.groovy.util.URLStreams;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+/**
+ * Looks for source file extensions in META-INF/services/org.codehaus.groovy.source.Extensions
+ */
+public class SourceExtensionHandler {
+
+ public static Set<String> getRegisteredExtensions(ClassLoader loader) {
+ Set<String> extensions = new LinkedHashSet<String>();
+ extensions.add("groovy");
+ try {
+ Enumeration<URL> globalServices = loader.getResources("META-INF/groovy/org.codehaus.groovy.source.Extensions");
+ if (!globalServices.hasMoreElements()) {
+ globalServices = loader.getResources("META-INF/services/org.codehaus.groovy.source.Extensions");
+ }
+ while (globalServices.hasMoreElements()) {
+ URL service = globalServices.nextElement();
+ try (BufferedReader svcIn = new BufferedReader(new InputStreamReader(URLStreams.openUncachedStream(service)))) {
+ String extension = svcIn.readLine();
+ while (extension != null) {
+ extension = extension.trim();
+ if (!extension.startsWith("#") && extension.length() > 0) {
+ extensions.add(extension);
+ }
+ extension = svcIn.readLine();
+ }
+ } catch (IOException ex) {
+ throw new GroovyRuntimeException("IO Exception attempting to load registered source extension " +
+ service.toExternalForm() + ". Exception: " + ex.toString());
+ }
+ }
+ } catch (IOException ex) {
+ throw new GroovyRuntimeException("IO Exception getting registered source extensions. Exception: " + ex.toString());
+ }
+ return extensions;
+ }
+}
diff --git a/src/main/java/org/codehaus/groovy/reflection/ParameterTypes.java b/src/main/java/org/codehaus/groovy/reflection/ParameterTypes.java
index ebeb771..6069036 100644
--- a/src/main/java/org/codehaus/groovy/reflection/ParameterTypes.java
+++ b/src/main/java/org/codehaus/groovy/reflection/ParameterTypes.java
@@ -1,385 +1,385 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.codehaus.groovy.reflection;
-
-import org.codehaus.groovy.GroovyBugError;
-import org.codehaus.groovy.runtime.MetaClassHelper;
-import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
-import org.codehaus.groovy.runtime.wrappers.Wrapper;
-
-import java.lang.reflect.Array;
-
-public class ParameterTypes {
- private static final Class[] NO_PARAMETERS = new Class[0];
-
- protected volatile Class[] nativeParamTypes;
- protected volatile CachedClass[] parameterTypes;
-
- protected boolean isVargsMethod;
-
- public ParameterTypes() {
- }
-
- public ParameterTypes(Class pt[]) {
- nativeParamTypes = pt;
- }
-
- public ParameterTypes(String pt[]) {
- nativeParamTypes = new Class[pt.length];
- for (int i = 0; i != pt.length; ++i) {
- try {
- nativeParamTypes[i] = Class.forName(pt[i]);
- } catch (ClassNotFoundException e) {
- NoClassDefFoundError err = new NoClassDefFoundError();
- err.initCause(e);
- throw err;
- }
- }
- }
-
- public ParameterTypes(CachedClass[] parameterTypes) {
- setParametersTypes(parameterTypes);
- }
-
- protected final void setParametersTypes(CachedClass[] pt) {
- this.parameterTypes = pt;
- isVargsMethod = pt.length > 0 && pt[pt.length - 1].isArray;
- }
-
- public CachedClass[] getParameterTypes() {
- if (parameterTypes == null) {
- getParametersTypes0();
- }
-
- return parameterTypes;
- }
-
- private synchronized void getParametersTypes0() {
- if (parameterTypes != null)
- return;
-
- Class[] npt = nativeParamTypes == null ? getPT() : nativeParamTypes;
- if (npt.length == 0) {
- nativeParamTypes = NO_PARAMETERS;
- setParametersTypes(CachedClass.EMPTY_ARRAY);
- } else {
-
- CachedClass[] pt = new CachedClass[npt.length];
- for (int i = 0; i != npt.length; ++i)
- pt[i] = ReflectionCache.getCachedClass(npt[i]);
-
- nativeParamTypes = npt;
- setParametersTypes(pt);
- }
- }
-
- public Class[] getNativeParameterTypes() {
- if (nativeParamTypes == null) {
- getNativeParameterTypes0();
- }
- return nativeParamTypes;
- }
-
- private synchronized void getNativeParameterTypes0() {
- if (nativeParamTypes != null)
- return;
-
- Class[] npt;
- if (parameterTypes != null) {
- npt = new Class[parameterTypes.length];
- for (int i = 0; i != parameterTypes.length; ++i) {
- npt[i] = parameterTypes[i].getTheClass();
- }
- } else
- npt = getPT();
- nativeParamTypes = npt;
- }
-
- protected Class[] getPT() {
- throw new UnsupportedOperationException(getClass().getName());
- }
-
- public boolean isVargsMethod() {
- return isVargsMethod;
- }
-
- public boolean isVargsMethod(Object[] arguments) {
- // Uncomment if at some point this method can be called before parameterTypes initialized
- // getParameterTypes();
- if (!isVargsMethod)
- return false;
-
- final int lenMinus1 = parameterTypes.length - 1;
- // -1 because the varg part is optional
- if (lenMinus1 == arguments.length) return true;
- if (lenMinus1 > arguments.length) return false;
- if (arguments.length > parameterTypes.length) return true;
-
- // only case left is arguments.length == parameterTypes.length
- Object last = arguments[arguments.length - 1];
- if (last == null) return true;
- Class clazz = last.getClass();
- return !clazz.equals(parameterTypes[lenMinus1].getTheClass());
-
- }
-
- public final Object[] coerceArgumentsToClasses(Object[] argumentArray) {
- // Uncomment if at some point this method can be called before parameterTypes initialized
- // getParameterTypes();
- argumentArray = correctArguments(argumentArray);
-
- final CachedClass[] pt = parameterTypes;
- final int len = argumentArray.length;
- for (int i = 0; i < len; i++) {
- final Object argument = argumentArray[i];
- if (argument != null) {
- argumentArray[i] = pt[i].coerceArgument(argument);
- }
- }
- return argumentArray;
- }
-
- public Object[] correctArguments(Object[] argumentArray) {
- // correct argumentArray's length
- if (argumentArray == null) {
- return MetaClassHelper.EMPTY_ARRAY;
- }
-
- final CachedClass[] pt = getParameterTypes();
- if (pt.length == 1 && argumentArray.length == 0) {
- if (isVargsMethod)
- return new Object[]{Array.newInstance(pt[0].getTheClass().getComponentType(), 0)};
- else
- return MetaClassHelper.ARRAY_WITH_NULL;
- }
-
- if (isVargsMethod && isVargsMethod(argumentArray)) {
- return fitToVargs(argumentArray, pt);
- }
-
- return argumentArray;
- }
-
- /**
- * this method is called when the number of arguments to a method is greater than 1
- * and if the method is a vargs method. This method will then transform the given
- * arguments to make the method callable
- *
- * @param argumentArrayOrig the arguments used to call the method
- * @param paramTypes the types of the parameters the method takes
- */
- private static Object[] fitToVargs(Object[] argumentArrayOrig, CachedClass[] paramTypes) {
- Class vargsClassOrig = paramTypes[paramTypes.length - 1].getTheClass().getComponentType();
- Class vargsClass = ReflectionCache.autoboxType(vargsClassOrig);
- Object[] argumentArray = argumentArrayOrig.clone();
- MetaClassHelper.unwrap(argumentArray);
-
- if (argumentArray.length == paramTypes.length - 1) {
- // the vargs argument is missing, so fill it with an empty array
- Object[] newArgs = new Object[paramTypes.length];
- System.arraycopy(argumentArray, 0, newArgs, 0, argumentArray.length);
- Object vargs = Array.newInstance(vargsClass, 0);
- newArgs[newArgs.length - 1] = vargs;
- return newArgs;
- } else if (argumentArray.length == paramTypes.length) {
- // the number of arguments is correct, but if the last argument
- // is no array we have to wrap it in a array. If the last argument
- // is null, then we don't have to do anything
- Object lastArgument = argumentArray[argumentArray.length - 1];
- if (lastArgument != null && !lastArgument.getClass().isArray()) {
- // no array so wrap it
- Object wrapped = makeCommonArray(argumentArray, paramTypes.length - 1, vargsClass);
- Object[] newArgs = new Object[paramTypes.length];
- System.arraycopy(argumentArray, 0, newArgs, 0, paramTypes.length - 1);
- newArgs[newArgs.length - 1] = wrapped;
- return newArgs;
- } else {
- // we may have to box the argument!
- return argumentArray;
- }
- } else if (argumentArray.length > paramTypes.length) {
- // the number of arguments is too big, wrap all exceeding elements
- // in an array, but keep the old elements that are no vargs
- Object[] newArgs = new Object[paramTypes.length];
- // copy arguments that are not a varg
- System.arraycopy(argumentArray, 0, newArgs, 0, paramTypes.length - 1);
- // create a new array for the vargs and copy them
- Object vargs = makeCommonArray(argumentArray, paramTypes.length - 1, vargsClass);
- newArgs[newArgs.length - 1] = vargs;
- return newArgs;
- } else {
- throw new GroovyBugError("trying to call a vargs method without enough arguments");
- }
- }
-
- private static Object makeCommonArray(Object[] arguments, int offset, Class baseClass) {
- Object[] result = (Object[]) Array.newInstance(baseClass, arguments.length - offset);
- for (int i = offset; i < arguments.length; i++) {
- Object v = arguments[i];
- v = DefaultTypeTransformation.castToType(v, baseClass);
- result[i - offset] = v;
- }
- return result;
- }
-
- public boolean isValidMethod(Class[] arguments) {
- if (arguments == null) return true;
-
- final int size = arguments.length;
- CachedClass[] pt = getParameterTypes();
- final int paramMinus1 = pt.length - 1;
-
- if (isVargsMethod && size >= paramMinus1)
- return isValidVarargsMethod(arguments, size, pt, paramMinus1);
- else if (pt.length == size)
- return isValidExactMethod(arguments, pt);
- else if (pt.length == 1 && size == 0 && !pt[0].isPrimitive)
- return true;
- return false;
- }
-
- private static boolean isValidExactMethod(Class[] arguments, CachedClass[] pt) {
- // lets check the parameter types match
- int size = pt.length;
- for (int i = 0; i < size; i++) {
- if (!pt[i].isAssignableFrom(arguments[i])) {
- return false;
- }
- }
- return true;
- }
-
- public boolean isValidExactMethod(Object[] args) {
- // lets check the parameter types match
- getParametersTypes0();
- int size = args.length;
- if (size != parameterTypes.length)
- return false;
-
- for (int i = 0; i < size; i++) {
- if (args[i] != null && !parameterTypes[i].isAssignableFrom(args[i].getClass())) {
- return false;
- }
- }
- return true;
- }
-
- public boolean isValidExactMethod(Class[] args) {
- // lets check the parameter types match
- getParametersTypes0();
- int size = args.length;
- if (size != parameterTypes.length)
- return false;
-
- for (int i = 0; i < size; i++) {
- if (args[i] != null && !parameterTypes[i].isAssignableFrom(args[i])) {
- return false;
- }
- }
- return true;
- }
-
- private static boolean testComponentAssignable(Class toTestAgainst, Class toTest) {
- Class component = toTest.getComponentType();
- if (component == null) return false;
- return MetaClassHelper.isAssignableFrom(toTestAgainst, component);
- }
-
- private static boolean isValidVarargsMethod(Class[] arguments, int size, CachedClass[] pt, int paramMinus1) {
- // first check normal number of parameters
- for (int i = 0; i < paramMinus1; i++) {
- if (pt[i].isAssignableFrom(arguments[i])) continue;
- return false;
- }
-
- // check direct match
- CachedClass varg = pt[paramMinus1];
- Class clazz = varg.getTheClass().getComponentType();
- if (size == pt.length &&
- (varg.isAssignableFrom(arguments[paramMinus1]) ||
- testComponentAssignable(clazz, arguments[paramMinus1]))) {
- return true;
- }
-
- // check varged
- for (int i = paramMinus1; i < size; i++) {
- if (MetaClassHelper.isAssignableFrom(clazz, arguments[i])) continue;
- return false;
- }
- return true;
- }
-
- public boolean isValidMethod(Object[] arguments) {
- if (arguments == null) return true;
-
- final int size = arguments.length;
- CachedClass[] paramTypes = getParameterTypes();
- final int paramMinus1 = paramTypes.length - 1;
-
- if (size >= paramMinus1 && paramTypes.length > 0 &&
- paramTypes[(paramMinus1)].isArray) {
- // first check normal number of parameters
- for (int i = 0; i < paramMinus1; i++) {
- if (paramTypes[i].isAssignableFrom(getArgClass(arguments[i]))) continue;
- return false;
- }
-
-
- // check direct match
- CachedClass varg = paramTypes[paramMinus1];
- Class clazz = varg.getTheClass().getComponentType();
- if (size == paramTypes.length &&
- (varg.isAssignableFrom(getArgClass(arguments[paramMinus1])) ||
- testComponentAssignable(clazz, getArgClass(arguments[paramMinus1])))) {
- return true;
- }
-
-
- // check varged
- for (int i = paramMinus1; i < size; i++) {
- if (MetaClassHelper.isAssignableFrom(clazz, getArgClass(arguments[i]))) continue;
- return false;
- }
- return true;
- } else if (paramTypes.length == size) {
- // lets check the parameter types match
- for (int i = 0; i < size; i++) {
- if (paramTypes[i].isAssignableFrom(getArgClass(arguments[i]))) continue;
- return false;
- }
- return true;
- } else if (paramTypes.length == 1 && size == 0 && !paramTypes[0].isPrimitive) {
- return true;
- }
- return false;
- }
-
- private static Class getArgClass(Object arg) {
- Class cls;
- if (arg == null) {
- cls = null;
- } else {
- if (arg instanceof Wrapper) {
- cls = ((Wrapper) arg).getType();
- } else
- cls = arg.getClass();
- }
- return cls;
- }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.codehaus.groovy.reflection;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.runtime.MetaClassHelper;
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+import org.codehaus.groovy.runtime.wrappers.Wrapper;
+
+import java.lang.reflect.Array;
+
+public class ParameterTypes {
+ private static final Class[] NO_PARAMETERS = new Class[0];
+
+ protected volatile Class[] nativeParamTypes;
+ protected volatile CachedClass[] parameterTypes;
+
+ protected boolean isVargsMethod;
+
+ public ParameterTypes() {
+ }
+
+ public ParameterTypes(Class pt[]) {
+ nativeParamTypes = pt;
+ }
+
+ public ParameterTypes(String pt[]) {
+ nativeParamTypes = new Class[pt.length];
+ for (int i = 0; i != pt.length; ++i) {
+ try {
+ nativeParamTypes[i] = Class.forName(pt[i]);
+ } catch (ClassNotFoundException e) {
+ NoClassDefFoundError err = new NoClassDefFoundError();
+ err.initCause(e);
+ throw err;
+ }
+ }
+ }
+
+ public ParameterTypes(CachedClass[] parameterTypes) {
+ setParametersTypes(parameterTypes);
+ }
+
+ protected final void setParametersTypes(CachedClass[] pt) {
+ this.parameterTypes = pt;
+ isVargsMethod = pt.length > 0 && pt[pt.length - 1].isArray;
+ }
+
+ public CachedClass[] getParameterTypes() {
+ if (parameterTypes == null) {
+ getParametersTypes0();
+ }
+
+ return parameterTypes;
+ }
+
+ private synchronized void getParametersTypes0() {
+ if (parameterTypes != null)
+ return;
+
+ Class[] npt = nativeParamTypes == null ? getPT() : nativeParamTypes;
+ if (npt.length == 0) {
+ nativeParamTypes = NO_PARAMETERS;
+ setParametersTypes(CachedClass.EMPTY_ARRAY);
+ } else {
+
+ CachedClass[] pt = new CachedClass[npt.length];
+ for (int i = 0; i != npt.length; ++i)
+ pt[i] = ReflectionCache.getCachedClass(npt[i]);
+
+ nativeParamTypes = npt;
+ setParametersTypes(pt);
+ }
+ }
+
+ public Class[] getNativeParameterTypes() {
+ if (nativeParamTypes == null) {
+ getNativeParameterTypes0();
+ }
+ return nativeParamTypes;
+ }
+
+ private synchronized void getNativeParameterTypes0() {
+ if (nativeParamTypes != null)
+ return;
+
+ Class[] npt;
+ if (parameterTypes != null) {
+ npt = new Class[parameterTypes.length];
+ for (int i = 0; i != parameterTypes.length; ++i) {
+ npt[i] = parameterTypes[i].getTheClass();
+ }
+ } else
+ npt = getPT();
+ nativeParamTypes = npt;
+ }
+
+ protected Class[] getPT() {
+ throw new UnsupportedOperationException(getClass().getName());
+ }
+
+ public boolean isVargsMethod() {
+ return isVargsMethod;
+ }
+
+ public boolean isVargsMethod(Object[] arguments) {
+ // Uncomment if at some point this method can be called before parameterTypes initialized
+ // getParameterTypes();
+ if (!isVargsMethod)
+ return false;
+
+ final int lenMinus1 = parameterTypes.length - 1;
+ // -1 because the varg part is optional
+ if (lenMinus1 == arguments.length) return true;
+ if (lenMinus1 > arguments.length) return false;
+ if (arguments.length > parameterTypes.length) return true;
+
+ // only case left is arguments.length == parameterTypes.length
+ Object last = arguments[arguments.length - 1];
+ if (last == null) return true;
+ Class clazz = last.getClass();
+ return !clazz.equals(parameterTypes[lenMinus1].getTheClass());
+
+ }
+
+ public final Object[] coerceArgumentsToClasses(Object[] argumentArray) {
+ // Uncomment if at some point this method can be called before parameterTypes initialized
+ // getParameterTypes();
+ argumentArray = correctArguments(argumentArray);
+
+ final CachedClass[] pt = parameterTypes;
+ final int len = argumentArray.length;
+ for (int i = 0; i < len; i++) {
+ final Object argument = argumentArray[i];
+ if (argument != null) {
+ argumentArray[i] = pt[i].coerceArgument(argument);
+ }
+ }
+ return argumentArray;
+ }
+
+ public Object[] correctArguments(Object[] argumentArray) {
+ // correct argumentArray's length
+ if (argumentArray == null) {
+ return MetaClassHelper.EMPTY_ARRAY;
+ }
+
+ final CachedClass[] pt = getParameterTypes();
+ if (pt.length == 1 && argumentArray.length == 0) {
+ if (isVargsMethod)
+ return new Object[]{Array.newInstance(pt[0].getTheClass().getComponentType(), 0)};
+ else
+ return MetaClassHelper.ARRAY_WITH_NULL;
+ }
+
+ if (isVargsMethod && isVargsMethod(argumentArray)) {
+ return fitToVargs(argumentArray, pt);
+ }
+
+ return argumentArray;
+ }
+
+ /**
+ * this method is called when the number of arguments to a method is greater than 1
+ * and if the method is a vargs method. This method will then transform the given
+ * arguments to make the method callable
+ *
+ * @param argumentArrayOrig the arguments used to call the method
+ * @param paramTypes the types of the parameters the method takes
+ */
+ private static Object[] fitToVargs(Object[] argumentArrayOrig, CachedClass[] paramTypes) {
+ Class vargsClassOrig = paramTypes[paramTypes.length - 1].getTheClass().getComponentType();
+ Class vargsClass = ReflectionCache.autoboxType(vargsClassOrig);
+ Object[] argumentArray = argumentArrayOrig.clone();
+ MetaClassHelper.unwrap(argumentArray);
+
+ if (argumentArray.length == paramTypes.length - 1) {
+ // the vargs argument is missing, so fill it with an empty array
+ Object[] newArgs = new Object[paramTypes.length];
+ System.arraycopy(argumentArray, 0, newArgs, 0, argumentArray.length);
+ Object vargs = Array.newInstance(vargsClass, 0);
+ newArgs[newArgs.length - 1] = vargs;
+ return newArgs;
+ } else if (argumentArray.length == paramTypes.length) {
+ // the number of arguments is correct, but if the last argument
+ // is no array we have to wrap it in a array. If the last argument
+ // is null, then we don't have to do anything
+ Object lastArgument = argumentArray[argumentArray.length - 1];
+ if (lastArgument != null && !lastArgument.getClass().isArray()) {
+ // no array so wrap it
+ Object wrapped = makeCommonArray(argumentArray, paramTypes.length - 1, vargsClass);
+ Object[] newArgs = new Object[paramTypes.length];
+ System.arraycopy(argumentArray, 0, newArgs, 0, paramTypes.length - 1);
+ newArgs[newArgs.length - 1] = wrapped;
+ return newArgs;
+ } else {
+ // we may have to box the argument!
+ return argumentArray;
+ }
+ } else if (argumentArray.length > paramTypes.length) {
+ // the number of arguments is too big, wrap all exceeding elements
+ // in an array, but keep the old elements that are no vargs
+ Object[] newArgs = new Object[paramTypes.length];
+ // copy arguments that are not a varg
+ System.arraycopy(argumentArray, 0, newArgs, 0, paramTypes.length - 1);
+ // create a new array for the vargs and copy them
+ Object vargs = makeCommonArray(argumentArray, paramTypes.length - 1, vargsClass);
+ newArgs[newArgs.length - 1] = vargs;
+ return newArgs;
+ } else {
+ throw new GroovyBugError("trying to call a vargs method without enough arguments");
+ }
+ }
+
+ private static Object makeCommonArray(Object[] arguments, int offset, Class baseClass) {
+ Object[] result = (Object[]) Array.newInstance(baseClass, arguments.length - offset);
+ for (int i = offset; i < arguments.length; i++) {
+ Object v = arguments[i];
+ v = DefaultTypeTransformation.castToType(v, baseClass);
+ result[i - offset] = v;
+ }
+ return result;
+ }
+
+ public boolean isValidMethod(Class[] arguments) {
+ if (arguments == null) return true;
+
+ final int size = arguments.length;
+ CachedClass[] pt = getParameterTypes();
+ final int paramMinus1 = pt.length - 1;
+
+ if (isVargsMethod && size >= paramMinus1)
+ return isValidVarargsMethod(arguments, size, pt, paramMinus1);
+ else if (pt.length == size)
+ return isValidExactMethod(arguments, pt);
+ else if (pt.length == 1 && size == 0 && !pt[0].isPrimitive)
+ return true;
+ return false;
+ }
+
+ private static boolean isValidExactMethod(Class[] arguments, CachedClass[] pt) {
+ // lets check the parameter types match
+ int size = pt.length;
+ for (int i = 0; i < size; i++) {
+ if (!pt[i].isAssignableFrom(arguments[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public boolean isValidExactMethod(Object[] args) {
+ // lets check the parameter types match
+ getParametersTypes0();
+ int size = args.length;
+ if (size != parameterTypes.length)
+ return false;
+
+ for (int i = 0; i < size; i++) {
+ if (args[i] != null && !parameterTypes[i].isAssignableFrom(args[i].getClass())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public boolean isValidExactMethod(Class[] args) {
+ // lets check the parameter types match
+ getParametersTypes0();
+ int size = args.length;
+ if (size != parameterTypes.length)
+ return false;
+
+ for (int i = 0; i < size; i++) {
+ if (args[i] != null && !parameterTypes[i].isAssignableFrom(args[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static boolean testComponentAssignable(Class toTestAgainst, Class toTest) {
+ Class component = toTest.getComponentType();
+ if (component == null) return false;
+ return MetaClassHelper.isAssignableFrom(toTestAgainst, component);
+ }
+
+ private static boolean isValidVarargsMethod(Class[] arguments, int size, CachedClass[] pt, int paramMinus1) {
+ // first check normal number of parameters
+ for (int i = 0; i < paramMinus1; i++) {
+ if (pt[i].isAssignableFrom(arguments[i])) continue;
+ return false;
+ }
+
+ // check direct match
+ CachedClass varg = pt[paramMinus1];
+ Class clazz = varg.getTheClass().getComponentType();
+ if (size == pt.length &&
+ (varg.isAssignableFrom(arguments[paramMinus1]) ||
+ testComponentAssignable(clazz, arguments[paramMinus1]))) {
+ return true;
+ }
+
+ // check varged
+ for (int i = paramMinus1; i < size; i++) {
+ if (MetaClassHelper.isAssignableFrom(clazz, arguments[i])) continue;
+ return false;
+ }
+ return true;
+ }
+
+ public boolean isValidMethod(Object[] arguments) {
+ if (arguments == null) return true;
+
+ final int size = arguments.length;
+ CachedClass[] paramTypes = getParameterTypes();
+ final int paramMinus1 = paramTypes.length - 1;
+
+ if (size >= paramMinus1 && paramTypes.length > 0 &&
+ paramTypes[(paramMinus1)].isArray) {
+ // first check normal number of parameters
+ for (int i = 0; i < paramMinus1; i++) {
+ if (paramTypes[i].isAssignableFrom(getArgClass(arguments[i]))) continue;
+ return false;
+ }
+
+
+ // check direct match
+ CachedClass varg = paramTypes[paramMinus1];
+ Class clazz = varg.getTheClass().getComponentType();
+ if (size == paramTypes.length &&
+ (varg.isAssignableFrom(getArgClass(arguments[paramMinus1])) ||
+ testComponentAssignable(clazz, getArgClass(arguments[paramMinus1])))) {
+ return true;
+ }
+
+
+ // check varged
+ for (int i = paramMinus1; i < size; i++) {
+ if (MetaClassHelper.isAssignableFrom(clazz, getArgClass(arguments[i]))) continue;
+ return false;
+ }
+ return true;
+ } else if (paramTypes.length == size) {
+ // lets check the parameter types match
+ for (int i = 0; i < size; i++) {
+ if (paramTypes[i].isAssignableFrom(getArgClass(arguments[i]))) continue;
+ return false;
+ }
+ return true;
+ } else if (paramTypes.length == 1 && size == 0 && !paramTypes[0].isPrimitive) {
+ return true;
+ }
+ return false;
+ }
+
+ private static Class getArgClass(Object arg) {
+ Class cls;
+ if (arg == null) {
+ cls = null;
+ } else {
+ if (arg instanceof Wrapper) {
+ cls = ((Wrapper) arg).getType();
+ } else
+ cls = arg.getClass();
+ }
+ return cls;
+ }
+}
diff --git a/src/main/java/org/codehaus/groovy/runtime/ConversionHandler.java b/src/main/java/org/codehaus/groovy/runtime/ConversionHandler.java
index 6ea07b2..2519b39 100644
--- a/src/main/java/org/codehaus/groovy/runtime/ConversionHandler.java
+++ b/src/main/java/org/codehaus/groovy/runtime/ConversionHandler.java
@@ -1,222 +1,222 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.codehaus.groovy.runtime;
-
-import groovy.lang.GroovyObject;
-import groovy.lang.GroovyRuntimeException;
-import groovy.lang.GroovySystem;
-import groovy.lang.MetaClass;
-import org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl;
-import org.codehaus.groovy.vmplugin.VMPlugin;
-import org.codehaus.groovy.vmplugin.VMPluginFactory;
-
-import java.io.Serializable;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.lang.reflect.Proxy;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * This class is a general adapter to map a call to a Java interface
- * to a given delegate.
- */
-public abstract class ConversionHandler implements InvocationHandler, Serializable {
- private final Object delegate;
- private static final long serialVersionUID = 1162833717190835227L;
- private final ConcurrentHashMap<Method, Object> handleCache;
- {
- if (VMPluginFactory.getPlugin().getVersion() >= 7) {
- handleCache = new ConcurrentHashMap<Method, Object>(16, 0.9f, 2);
- } else {
- handleCache = null;
- }
- }
-
- private MetaClass metaClass;
-
- /**
- * Creates a ConversionHandler with an delegate.
- *
- * @param delegate the delegate
- * @throws IllegalArgumentException if the given delegate is null
- */
- public ConversionHandler(Object delegate) {
- if (delegate == null) {
- throw new IllegalArgumentException("delegate must not be null");
- }
- this.delegate = delegate;
- }
-
- /**
- * Returns the delegate.
- *
- * @return the delegate
- */
- public Object getDelegate() {
- return delegate;
- }
-
- /**
- * This method is a default implementation for the invoke method given in
- * InvocationHandler. Any call to a method with a declaring class that is
- * not Object, excluding toString() and default methods is redirected to invokeCustom.
- * <p>
- * Methods like equals and hashcode are called on the class itself instead
- * of the delegate because they are considered fundamental methods that should
- * not be overwritten. The toString() method gets special treatment as it is
- * deemed to be a method that you might wish to override when called from Groovy.
- * Interface default methods from Java 8 on the other hand are considered being
- * default implementations you don't normally want to change. So they are called
- * directly too
- * </p><p>
- * In many scenarios, it is better to overwrite the invokeCustom method where
- * the core Object related methods are filtered out.
- *</p>
- * @param proxy the proxy
- * @param method the method
- * @param args the arguments
- * @return the result of the invocation by method or delegate
- * @throws Throwable if caused by the delegate or the method
- * @see #invokeCustom(Object, Method, Object[])
- * @see InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
- */
- public Object invoke(final Object proxy, Method method, Object[] args) throws Throwable {
- if (handleCache != null && isDefaultMethod(method) && !defaultOverridden(method)) {
- final VMPlugin plugin = VMPluginFactory.getPlugin();
- Object handle = handleCache.computeIfAbsent(method, m -> plugin.getInvokeSpecialHandle(m, proxy));
- return plugin.invokeHandle(handle, args);
- }
-
- if (!checkMethod(method)) {
- try {
- if (method.getDeclaringClass() == GroovyObject.class) {
- if ("getMetaClass".equals(method.getName())) {
- return getMetaClass(proxy);
- } else if ("setMetaClass".equals(method.getName())) {
- return setMetaClass((MetaClass) args[0]);
- }
- }
- return invokeCustom(proxy, method, args);
- } catch (GroovyRuntimeException gre) {
- throw ScriptBytecodeAdapter.unwrap(gre);
- }
- }
-
- try {
- return method.invoke(this, args);
- } catch (InvocationTargetException ite) {
- throw ite.getTargetException();
- }
- }
-
- private boolean defaultOverridden(Method method) {
- return delegate instanceof Map && ((Map) delegate).containsKey(method.getName());
- }
-
- protected boolean isDefaultMethod(Method method) {
- return ((method.getModifiers() & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) ==
- Modifier.PUBLIC) && method.getDeclaringClass().isInterface();
- }
-
- protected boolean checkMethod(Method method) {
- return isCoreObjectMethod(method);
- }
-
- /**
- * This method is called for all Methods not defined on Object.
- * The delegate should be called here.
- *
- * @param proxy the proxy
- * @param method the method
- * @param args the arguments
- * @return the result of the invocation of the delegate
- * @throws Throwable any exception causes by the delegate
- * @see #invoke(Object, Method, Object[])
- * @see InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
- */
- public abstract Object invokeCustom(Object proxy, Method method, Object[] args) throws Throwable;
-
- /**
- * Indicates whether some other object is "equal to" this one.
- * The delegate is used if the class of the parameter and the
- * current class are equal. In other cases the method will return
- * false. The exact class is here used, if inheritance is needed,
- * this method must be overwritten.
- *
- * @see java.lang.Object#equals(java.lang.Object)
- */
- public boolean equals(Object obj) {
- if (obj instanceof Proxy) {
- obj = Proxy.getInvocationHandler(obj);
- }
-
- if (obj instanceof ConversionHandler) {
- return (((ConversionHandler) obj).getDelegate()).equals(delegate);
- } else {
- return false;
- }
- }
-
- /**
- * Returns a hash code value for the delegate.
- *
- * @see java.lang.Object#hashCode()
- */
- public int hashCode() {
- return delegate.hashCode();
- }
-
- /**
- * Returns a String version of the delegate.
- *
- * @see java.lang.Object#toString()
- */
- public String toString() {
- return delegate.toString();
- }
-
- /**
- * Checks whether a method is a core method from java.lang.Object.
- * Such methods often receive special treatment because they are
- * deemed fundamental enough to not be tampered with.
- *
- * @param method the method to check
- * @return true if the method is deemed to be a core method
- */
- public static boolean isCoreObjectMethod(Method method) {
- return Object.class.equals(method.getDeclaringClass());
- }
-
- private MetaClass setMetaClass(MetaClass mc) {
- metaClass = mc;
- return mc;
- }
-
- private MetaClass getMetaClass(Object proxy) {
- MetaClass mc = metaClass;
- if (mc == null) {
- mc = ((MetaClassRegistryImpl) GroovySystem.getMetaClassRegistry()).getMetaClass(proxy);
- metaClass = mc;
- }
- return mc;
- }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.codehaus.groovy.runtime;
+
+import groovy.lang.GroovyObject;
+import groovy.lang.GroovyRuntimeException;
+import groovy.lang.GroovySystem;
+import groovy.lang.MetaClass;
+import org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl;
+import org.codehaus.groovy.vmplugin.VMPlugin;
+import org.codehaus.groovy.vmplugin.VMPluginFactory;
+
+import java.io.Serializable;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Proxy;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * This class is a general adapter to map a call to a Java interface
+ * to a given delegate.
+ */
+public abstract class ConversionHandler implements InvocationHandler, Serializable {
+ private final Object delegate;
+ private static final long serialVersionUID = 1162833717190835227L;
+ private final ConcurrentHashMap<Method, Object> handleCache;
+ {
+ if (VMPluginFactory.getPlugin().getVersion() >= 7) {
+ handleCache = new ConcurrentHashMap<Method, Object>(16, 0.9f, 2);
+ } else {
+ handleCache = null;
+ }
+ }
+
+ private MetaClass metaClass;
+
+ /**
+ * Creates a ConversionHandler with an delegate.
+ *
+ * @param delegate the delegate
+ * @throws IllegalArgumentException if the given delegate is null
+ */
+ public ConversionHandler(Object delegate) {
+ if (delegate == null) {
+ throw new IllegalArgumentException("delegate must not be null");
+ }
+ this.delegate = delegate;
+ }
+
+ /**
+ * Returns the delegate.
+ *
+ * @return the delegate
+ */
+ public Object getDelegate() {
+ return delegate;
+ }
+
+ /**
+ * This method is a default implementation for the invoke method given in
+ * InvocationHandler. Any call to a method with a declaring class that is
+ * not Object, excluding toString() and default methods is redirected to invokeCustom.
+ * <p>
+ * Methods like equals and hashcode are called on the class itself instead
+ * of the delegate because they are considered fundamental methods that should
+ * not be overwritten. The toString() method gets special treatment as it is
+ * deemed to be a method that you might wish to override when called from Groovy.
+ * Interface default methods from Java 8 on the other hand are considered being
+ * default implementations you don't normally want to change. So they are called
+ * directly too
+ * </p><p>
+ * In many scenarios, it is better to overwrite the invokeCustom method where
+ * the core Object related methods are filtered out.
+ *</p>
+ * @param proxy the proxy
+ * @param method the method
+ * @param args the arguments
+ * @return the result of the invocation by method or delegate
+ * @throws Throwable if caused by the delegate or the method
+ * @see #invokeCustom(Object, Method, Object[])
+ * @see InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
+ */
+ public Object invoke(final Object proxy, Method method, Object[] args) throws Throwable {
+ if (handleCache != null && isDefaultMethod(method) && !defaultOverridden(method)) {
+ final VMPlugin plugin = VMPluginFactory.getPlugin();
+ Object handle = handleCache.computeIfAbsent(method, m -> plugin.getInvokeSpecialHandle(m, proxy));
+ return plugin.invokeHandle(handle, args);
+ }
+
+ if (!checkMethod(method)) {
+ try {
+ if (method.getDeclaringClass() == GroovyObject.class) {
+ if ("getMetaClass".equals(method.getName())) {
+ return getMetaClass(proxy);
+ } else if ("setMetaClass".equals(method.getName())) {
+ return setMetaClass((MetaClass) args[0]);
+ }
+ }
+ return invokeCustom(proxy, method, args);
+ } catch (GroovyRuntimeException gre) {
+ throw ScriptBytecodeAdapter.unwrap(gre);
+ }
+ }
+
+ try {
+ return method.invoke(this, args);
+ } catch (InvocationTargetException ite) {
+ throw ite.getTargetException();
+ }
+ }
+
+ private boolean defaultOverridden(Method method) {
+ return delegate instanceof Map && ((Map) delegate).containsKey(method.getName());
+ }
+
+ protected boolean isDefaultMethod(Method method) {
+ return ((method.getModifiers() & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) ==
+ Modifier.PUBLIC) && method.getDeclaringClass().isInterface();
+ }
+
+ protected boolean checkMethod(Method method) {
+ return isCoreObjectMethod(method);
+ }
+
+ /**
+ * This method is called for all Methods not defined on Object.
+ * The delegate should be called here.
+ *
+ * @param proxy the proxy
+ * @param method the method
+ * @param args the arguments
+ * @return the result of the invocation of the delegate
+ * @throws Throwable any exception causes by the delegate
+ * @see #invoke(Object, Method, Object[])
+ * @see InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
+ */
+ public abstract Object invokeCustom(Object proxy, Method method, Object[] args) throws Throwable;
+
+ /**
+ * Indicates whether some other object is "equal to" this one.
+ * The delegate is used if the class of the parameter and the
+ * current class are equal. In other cases the method will return
+ * false. The exact class is here used, if inheritance is needed,
+ * this method must be overwritten.
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ public boolean equals(Object obj) {
+ if (obj instanceof Proxy) {
+ obj = Proxy.getInvocationHandler(obj);
+ }
+
+ if (obj instanceof ConversionHandler) {
+ return (((ConversionHandler) obj).getDelegate()).equals(delegate);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Returns a hash code value for the delegate.
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ public int hashCode() {
+ return delegate.hashCode();
+ }
+
+ /**
+ * Returns a String version of the delegate.
+ *
+ * @see java.lang.Object#toString()
+ */
+ public String toString() {
+ return delegate.toString();
+ }
+
+ /**
+ * Checks whether a method is a core method from java.lang.Object.
+ * Such methods often receive special treatment because they are
+ * deemed fundamental enough to not be tampered with.
+ *
+ * @param method the method to check
+ * @return true if the method is deemed to be a core method
+ */
+ public static boolean isCoreObjectMethod(Method method) {
+ return Object.class.equals(method.getDeclaringClass());
+ }
+
+ private MetaClass setMetaClass(MetaClass mc) {
+ metaClass = mc;
+ return mc;
+ }
+
+ private MetaClass getMetaClass(Object proxy) {
+ MetaClass mc = metaClass;
+ if (mc == null) {
+ mc = ((MetaClassRegistryImpl) GroovySystem.getMetaClassRegistry()).getMetaClass(proxy);
+ metaClass = mc;
+ }
+ return mc;
+ }
+}
diff --git a/src/main/java/org/codehaus/groovy/runtime/ConvertedClosure.java b/src/main/java/org/codehaus/groovy/runtime/ConvertedClosure.java
index 84a627f..f21b143 100644
--- a/src/main/java/org/codehaus/groovy/runtime/ConvertedClosure.java
+++ b/src/main/java/org/codehaus/groovy/runtime/ConvertedClosure.java
@@ -1,54 +1,54 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.codehaus.groovy.runtime;
-
-import groovy.lang.Closure;
-
-import java.io.Serializable;
-import java.lang.reflect.Method;
-
-/**
- * This class is a general adapter to adapt a closure to any Java interface.
- */
-public class ConvertedClosure extends ConversionHandler implements Serializable {
- private final String methodName;
- private static final long serialVersionUID = 1162833713450835227L;
-
- /**
- * to create a ConvertedClosure object.
- * @param closure the closure object.
- */
- public ConvertedClosure(Closure closure, String method) {
- super(closure);
- this.methodName = method;
- }
-
- public ConvertedClosure(Closure closure) {
- this(closure,null);
- }
-
- @Override
- public Object invokeCustom(Object proxy, Method method, Object[] args)
- throws Throwable {
- if (methodName!=null && !methodName.equals(method.getName())) return null;
- return ((Closure) getDelegate()).call(args);
- }
-
-}
-
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.codehaus.groovy.runtime;
+
+import groovy.lang.Closure;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+
+/**
+ * This class is a general adapter to adapt a closure to any Java interface.
+ */
+public class ConvertedClosure extends ConversionHandler implements Serializable {
+ private final String methodName;
+ private static final long serialVersionUID = 1162833713450835227L;
+
+ /**
+ * to create a ConvertedClosure object.
+ * @param closure the closure object.
+ */
+ public ConvertedClosure(Closure closure, String method) {
+ super(closure);
+ this.methodName = method;
+ }
+
+ public ConvertedClosure(Closure closure) {
+ this(closure,null);
+ }
+
+ @Override
+ public Object invokeCustom(Object proxy, Method method, Object[] args)
+ throws Throwable {
+ if (methodName!=null && !methodName.equals(method.getName())) return null;
+ return ((Closure) getDelegate()).call(args);
+ }
+
+}
+
diff --git a/src/main/java/org/codehaus/groovy/runtime/EncodingGroovyMethodsSupport.java b/src/main/java/org/codehaus/groovy/runtime/EncodingGroovyMethodsSupport.java
index 24929a8..9a97fc3 100644
--- a/src/main/java/org/codehaus/groovy/runtime/EncodingGroovyMethodsSupport.java
+++ b/src/main/java/org/codehaus/groovy/runtime/EncodingGroovyMethodsSupport.java
@@ -1,90 +1,90 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.codehaus.groovy.runtime;
-
-/**
- * Keep this constant in a separate file as it is troublesome for Antlr to parse for doc purposes.
- */
-public class EncodingGroovyMethodsSupport {
- static final byte[] TRANSLATE_TABLE = (
- "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
- // \t \n \r
- + "\u0042\u0041\u0041\u0042\u0042\u0041\u0042\u0042"
- //
- + "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
- //
- + "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
- // sp ! " # $ % & '
- + "\u0041\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
- // ( ) * + , - . /
- + "\u0042\u0042\u0042\u003E\u0042\u0042\u0042\u003F"
- // 0 1 2 3 4 5 6 7
- + "\u0034\u0035\u0036\u0037\u0038\u0039\u003A\u003B"
- // 8 9 : ; < = > ?
- + "\u003C\u003D\u0042\u0042\u0042\u0040\u0042\u0042"
- // @ A B C D E F G
- + "\u0042\u0000\u0001\u0002\u0003\u0004\u0005\u0006"
- // H I J K L M N O
- + "\u0007\u0008\t\n\u000B\u000C\r\u000E"
- // P Q R S T U V W
- + "\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016"
- // X Y Z [ \ ] ^ _
- + "\u0017\u0018\u0019\u0042\u0042\u0042\u0042\u0042"
- // ' a b c d e f g
- + "\u0042\u001A\u001B\u001C\u001D\u001E\u001F\u0020"
- // h i j k l m n o
- + "\u0021\"\u0023\u0024\u0025\u0026\u0027\u0028"
- // p q r s t u v w
- + "\u0029\u002A\u002B\u002C\u002D\u002E\u002F\u0030"
- // x y z
- + "\u0031\u0032\u0033").getBytes();
-
- static final byte[] TRANSLATE_TABLE_URLSAFE = (
- "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
- // \t \n \r
- + "\u0042\u0041\u0041\u0042\u0042\u0041\u0042\u0042"
- //
- + "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
- //
- + "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
- // sp ! " # $ % & '
- + "\u0041\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
- // ( ) * + , - . /
- + "\u0042\u0042\u0042\u0042\u0042\u003E\u0042\u0042"
- // 0 1 2 3 4 5 6 7
- + "\u0034\u0035\u0036\u0037\u0038\u0039\u003A\u003B"
- // 8 9 : ; < = > ?
- + "\u003C\u003D\u0042\u0042\u0042\u0040\u0042\u0042"
- // @ A B C D E F G
- + "\u0042\u0000\u0001\u0002\u0003\u0004\u0005\u0006"
- // H I J K L M N O
- + "\u0007\u0008\t\n\u000B\u000C\r\u000E"
- // P Q R S T U V W
- + "\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016"
- // X Y Z [ \ ] ^ _
- + "\u0017\u0018\u0019\u0042\u0042\u0042\u0042\u003F"
- // ' a b c d e f g
- + "\u0042\u001A\u001B\u001C\u001D\u001E\u001F\u0020"
- // h i j k l m n o
- + "\u0021\"\u0023\u0024\u0025\u0026\u0027\u0028"
- // p q r s t u v w
- + "\u0029\u002A\u002B\u002C\u002D\u002E\u002F\u0030"
- // x y z
- + "\u0031\u0032\u0033").getBytes();
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.codehaus.groovy.runtime;
+
+/**
+ * Keep this constant in a separate file as it is troublesome for Antlr to parse for doc purposes.
+ */
+public class EncodingGroovyMethodsSupport {
+ static final byte[] TRANSLATE_TABLE = (
+ "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
+ // \t \n \r
+ + "\u0042\u0041\u0041\u0042\u0042\u0041\u0042\u0042"
+ //
+ + "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
+ //
+ + "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
+ // sp ! " # $ % & '
+ + "\u0041\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
+ // ( ) * + , - . /
+ + "\u0042\u0042\u0042\u003E\u0042\u0042\u0042\u003F"
+ // 0 1 2 3 4 5 6 7
+ + "\u0034\u0035\u0036\u0037\u0038\u0039\u003A\u003B"
+ // 8 9 : ; < = > ?
+ + "\u003C\u003D\u0042\u0042\u0042\u0040\u0042\u0042"
+ // @ A B C D E F G
+ + "\u0042\u0000\u0001\u0002\u0003\u0004\u0005\u0006"
+ // H I J K L M N O
+ + "\u0007\u0008\t\n\u000B\u000C\r\u000E"
+ // P Q R S T U V W
+ + "\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016"
+ // X Y Z [ \ ] ^ _
+ + "\u0017\u0018\u0019\u0042\u0042\u0042\u0042\u0042"
+ // ' a b c d e f g
+ + "\u0042\u001A\u001B\u001C\u001D\u001E\u001F\u0020"
+ // h i j k l m n o
+ + "\u0021\"\u0023\u0024\u0025\u0026\u0027\u0028"
+ // p q r s t u v w
+ + "\u0029\u002A\u002B\u002C\u002D\u002E\u002F\u0030"
+ // x y z
+ + "\u0031\u0032\u0033").getBytes();
+
+ static final byte[] TRANSLATE_TABLE_URLSAFE = (
+ "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
+ // \t \n \r
+ + "\u0042\u0041\u0041\u0042\u0042\u0041\u0042\u0042"
+ //
+ + "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
+ //
+ + "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
+ // sp ! " # $ % & '
+ + "\u0041\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
+ // ( ) * + , - . /
+ + "\u0042\u0042\u0042\u0042\u0042\u003E\u0042\u0042"
+ // 0 1 2 3 4 5 6 7
+ + "\u0034\u0035\u0036\u0037\u0038\u0039\u003A\u003B"
+ // 8 9 : ; < = > ?
+ + "\u003C\u003D\u0042\u0042\u0042\u0040\u0042\u0042"
+ // @ A B C D E F G
+ + "\u0042\u0000\u0001\u0002\u0003\u0004\u0005\u0006"
+ // H I J K L M N O
+ + "\u0007\u0008\t\n\u000B\u000C\r\u000E"
+ // P Q R S T U V W
+ + "\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016"
+ // X Y Z [ \ ] ^ _
+ + "\u0017\u0018\u0019\u0042\u0042\u0042\u0042\u003F"
+ // ' a b c d e f g
+ + "\u0042\u001A\u001B\u001C\u001D\u001E\u001F\u0020"
+ // h i j k l m n o
+ + "\u0021\"\u0023\u0024\u0025\u0026\u0027\u0028"
+ // p q r s t u v w
+ + "\u0029\u002A\u002B\u002C\u002D\u002E\u002F\u0030"
+ // x y z
+ + "\u0031\u0032\u0033").getBytes();
+}
diff --git a/src/main/java/org/codehaus/groovy/runtime/GStringImpl.java b/src/main/java/org/codehaus/groovy/runtime/GStringImpl.java
index 7e5beec..b1c66fe 100644
--- a/src/main/java/org/codehaus/groovy/runtime/GStringImpl.java
+++ b/src/main/java/org/codehaus/groovy/runtime/GStringImpl.java
@@ -1,64 +1,64 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.codehaus.groovy.runtime;
-
-import groovy.lang.GString;
-
-/**
- * Default implementation of a GString used by the compiler. A GString
- * consist of a list of values and strings which can be combined to
- * create a new String.
- *
- * @see groovy.lang.GString
- */
-public class GStringImpl extends GString {
- private static final long serialVersionUID = 3581289038662723858L;
- private String[] strings;
-
- /**
- * Create a new GString with values and strings.
- * <p>
- * Each value is prefixed by a string, after the last value
- * an additional String might be used. This means
- * <code>strings.length == values.length || strings.length == values.length + 1</code>.
- * <p>
- * <b>NOTE:</b> The lengths are <b>not</b> checked. Using different lengths might result
- * in unpredictable behaviour.
- *
- * @param values the value parts
- * @param strings the string parts
- */
- public GStringImpl(Object[] values, String[] strings) {
- super(values);
- this.strings = strings;
- }
-
- /**
- * Get the strings of this GString.
- * <p>
- * This methods returns the same array as used in the constructor. Changing
- * the values will result in changes of the GString. It is not recommended
- * to do so.
- */
- public String[] getStrings() {
- return strings;
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.codehaus.groovy.runtime;
+
+import groovy.lang.GString;
+
+/**
+ * Default implementation of a GString used by the compiler. A GString
+ * consist of a list of values and strings which can be combined to
+ * create a new String.
+ *
+ * @see groovy.lang.GString
+ */
+public class GStringImpl extends GString {
+ private static final long serialVersionUID = 3581289038662723858L;
+ private String[] strings;
+
+ /**
+ * Create a new GString with values and strings.
+ * <p>
+ * Each value is prefixed by a string, after the last value
+ * an additional String might be used. This means
+ * <code>strings.length == values.length || strings.length == values.length + 1</code>.
+ * <p>
+ * <b>NOTE:</b> The lengths are <b>not</b> checked. Using different lengths might result
+ * in unpredictable behaviour.
+ *
+ * @param values the value parts
+ * @param strings the string parts
+ */
+ public GStringImpl(Object[] values, String[] strings) {
+ super(values);
+ this.strings = strings;
+ }
+
+ /**
+ * Get the strings of this GString.
+ * <p>
+ * This methods returns the same array as used in the constructor. Changing
+ * the values will result in changes of the GString. It is not recommended
+ * to do so.
+ */
+ public String[] getStrings() {
+ return strings;
+ }
+
+}
diff --git a/src/main/java/org/codehaus/groovy/runtime/NumberAwareComparator.java b/src/main/java/org/codehaus/groovy/runtime/NumberAwareComparator.java
index c44a48e..6a11b03 100644
--- a/src/main/java/org/codehaus/groovy/runtime/NumberAwareComparator.java
+++ b/src/main/java/org/codehaus/groovy/runtime/NumberAwareComparator.java
@@ -1,56 +1,56 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.codehaus.groovy.runtime;
-
-import groovy.lang.GroovyRuntimeException;
-import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
-
-import java.io.Serializable;
-import java.util.Comparator;
-
-/**
- * Compares two objects using Groovy's friendly comparison algorithm, i.e.
- * handles nulls gracefully (nul being less than everything else) and
- * performs numeric type coercion if required.
- */
-public class NumberAwareComparator<T> implements Comparator<T>, Serializable {
- private static final long serialVersionUID = 9017657289076651660L;
-
- public int compare(T o1, T o2) {
- try {
- return DefaultTypeTransformation.compareTo(o1, o2);
- } catch (ClassCastException | IllegalArgumentException | GroovyRuntimeException cce) {
- /* ignore */
- }
- // since the object does not have a valid compareTo method
- // we compare using the hashcodes. null cases are handled by
- // DefaultTypeTransformation.compareTo
- // This is not exactly a mathematical valid approach, since we compare object
- // that cannot be compared. To avoid strange side effects we do a pseudo order
- // using hashcodes, but without equality. Since then an x and y with the same
- // hashcodes will behave different depending on if we compare x with y or
- // x with y, the result might be unstable as well. Setting x and y to equal
- // may mean the removal of x or y in a sorting operation, which we don't want.
- int x1 = o1.hashCode();
- int x2 = o2.hashCode();
- if (x1 == x2 && o1.equals(o2)) return 0;
- if (x1 > x2) return 1;
- return -1;
- }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.codehaus.groovy.runtime;
+
+import groovy.lang.GroovyRuntimeException;
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+
+import java.io.Serializable;
+import java.util.Comparator;
+
+/**
+ * Compares two objects using Groovy's friendly comparison algorithm, i.e.
+ * handles nulls gracefully (nul being less than everything else) and
+ * performs numeric type coercion if required.
+ */
+public class NumberAwareComparator<T> implements Comparator<T>, Serializable {
+ private static final long serialVersionUID = 9017657289076651660L;
+
+ public int compare(T o1, T o2) {
+ try {
+ return DefaultTypeTransformation.compareTo(o1, o2);
+ } catch (ClassCastException | IllegalArgumentException | GroovyRuntimeException cce) {
+ /* ignore */
+ }
+ // since the object does not have a valid compareTo method
+ // we compare using the hashcodes. null cases are handled by
+ // DefaultTypeTransformation.compareTo
+ // This is not exactly a mathematical valid approach, since we compare object
+ // that cannot be compared. To avoid strange side effects we do a pseudo order
+ // using hashcodes, but without equality. Since then an x and y with the same
+ // hashcodes will behave different depending on if we compare x with y or
+ // x with y, the result might be unstable as well. Setting x and y to equal
+ // may mean the removal of x or y in a sorting operation, which we don't want.
+ int x1 = o1.hashCode();
+ int x2 = o2.hashCode();
+ if (x1 == x2 && o1.equals(o2)) return 0;
+ if (x1 > x2) return 1;
+ return -1;
+ }
+}
diff --git a/src/main/java/org/codehaus/groovy/runtime/dgmimpl/arrays/CharacterArrayPutAtMetaMethod.java b/src/main/java/org/codehaus/groovy/runtime/dgmimpl/arrays/CharacterArrayPutAtMetaMethod.java
index 053b7d4..039e21c 100644
--- a/src/main/java/org/codehaus/groovy/runtime/dgmimpl/arrays/CharacterArrayPutAtMetaMethod.java
+++ b/src/main/java/org/codehaus/groovy/runtime/dgmimpl/arrays/CharacterArrayPutAtMetaMethod.java
@@ -1,86 +1,86 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.codehaus.groovy.runtime.dgmimpl.arrays;
-
-import groovy.lang.MetaClassImpl;
-import groovy.lang.MetaMethod;
-import org.codehaus.groovy.reflection.CachedClass;
-import org.codehaus.groovy.reflection.ReflectionCache;
-import org.codehaus.groovy.runtime.callsite.CallSite;
-import org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite;
-import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
-
-public class CharacterArrayPutAtMetaMethod extends ArrayPutAtMetaMethod {
- private static final CachedClass OBJECT_CLASS = ReflectionCache.OBJECT_CLASS;
- private static final CachedClass ARR_CLASS = ReflectionCache.getCachedClass(char[].class);
- private static final CachedClass[] PARAM_CLASS_ARR = new CachedClass[]{INTEGER_CLASS, OBJECT_CLASS};
-
- public CharacterArrayPutAtMetaMethod() {
- parameterTypes = PARAM_CLASS_ARR;
- }
-
- public final CachedClass getDeclaringClass() {
- return ARR_CLASS;
- }
-
- public Object invoke(Object object, Object[] args) {
- final char[] objects = (char[]) object;
- final int index = normaliseIndex((Integer) args[0], objects.length);
- objects[index] = DefaultTypeTransformation.getCharFromSizeOneString(args[1]);
- return null;
- }
-
- public CallSite createPojoCallSite(CallSite site, MetaClassImpl metaClass, MetaMethod metaMethod, Class[] params, Object receiver, Object[] args) {
- if (!(args[0] instanceof Integer) || !(args[1] instanceof Character))
- return PojoMetaMethodSite.createNonAwareCallSite(site, metaClass, metaMethod, params, args);
- else
- return new MyPojoMetaMethodSite(site, metaClass, metaMethod, params);
- }
-
- private static class MyPojoMetaMethodSite extends PojoMetaMethodSite {
- public MyPojoMetaMethodSite(CallSite site, MetaClassImpl metaClass, MetaMethod metaMethod, Class[] params) {
- super(site, metaClass, metaMethod, params);
- }
-
- public Object call(Object receiver, Object[] args) throws Throwable {
- if ((receiver instanceof char[] && args[0] instanceof Integer && args[1] instanceof Character)
- && checkPojoMetaClass()) {
- final char[] objects = (char[]) receiver;
- objects[normaliseIndex((Integer) args[0], objects.length)] = (Character) args[1];
- return null;
- } else
- return super.call(receiver, args);
- }
-
- public Object call(Object receiver, Object arg1, Object arg2) throws Throwable {
- if (checkPojoMetaClass()) {
- try {
- final char[] objects = (char[]) receiver;
- objects[normaliseIndex((Integer) arg1, objects.length)] = (Character) arg2;
- return null;
- }
- catch (ClassCastException e) {
- if ((receiver instanceof char[]) && (arg1 instanceof Integer))
- throw e;
- }
- }
- return super.call(receiver, arg1, arg2);
- }
- }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.codehaus.groovy.runtime.dgmimpl.arrays;
+
+import groovy.lang.MetaClassImpl;
+import groovy.lang.MetaMethod;
+import org.codehaus.groovy.reflection.CachedClass;
+import org.codehaus.groovy.reflection.ReflectionCache;
+import org.codehaus.groovy.runtime.callsite.CallSite;
+import org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite;
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+
+public class CharacterArrayPutAtMetaMethod extends ArrayPutAtMetaMethod {
+ private static final CachedClass OBJECT_CLASS = ReflectionCache.OBJECT_CLASS;
+ private static final CachedClass ARR_CLASS = ReflectionCache.getCachedClass(char[].class);
+ private static final CachedClass[] PARAM_CLASS_ARR = new CachedClass[]{INTEGER_CLASS, OBJECT_CLASS};
+
+ public CharacterArrayPutAtMetaMethod() {
+ parameterTypes = PARAM_CLASS_ARR;
+ }
+
+ public final CachedClass getDeclaringClass() {
+ return ARR_CLASS;
+ }
+
+ public Object invoke(Object object, Object[] args) {
+ final char[] objects = (char[]) object;
+ final int index = normaliseIndex((Integer) args[0], objects.length);
+ objects[index] = DefaultTypeTransformation.getCharFromSizeOneString(args[1]);
+ return null;
+ }
+
+ public CallSite createPojoCallSite(CallSite site, MetaClassImpl metaClass, MetaMethod metaMethod, Class[] params, Object receiver, Object[] args) {
+ if (!(args[0] instanceof Integer) || !(args[1] instanceof Character))
+ return PojoMetaMethodSite.createNonAwareCallSite(site, metaClass, metaMethod, params, args);
+ else
+ return new MyPojoMetaMethodSite(site, metaClass, metaMethod, params);
+ }
+
+ private static class MyPojoMetaMethodSite extends PojoMetaMethodSite {
+ public MyPojoMetaMethodSite(CallSite site, MetaClassImpl metaClass, MetaMethod metaMethod, Class[] params) {
+ super(site, metaClass, metaMethod, params);
+ }
+
+ public Object call(Object receiver, Object[] args) throws Throwable {
+ if ((receiver instanceof char[] && args[0] instanceof Integer && args[1] instanceof Character)
+ && checkPojoMetaClass()) {
+ final char[] objects = (char[]) receiver;
+ objects[normaliseIndex((Integer) args[0], objects.length)] = (Character) args[1];
+ return null;
+ } else
+ return super.call(receiver, args);
+ }
+
+ public Object call(Object receiver, Object arg1, Object arg2) throws Throwable {
+ if (checkPojoMetaClass()) {
+ try {
+ final char[] objects = (char[]) receiver;
+ objects[normaliseIndex((Integer) arg1, objects.length)] = (Character) arg2;
+ return null;
+ }
+ catch (ClassCastException e) {
+ if ((receiver instanceof char[]) && (arg1 instanceof Integer))
+ throw e;
+ }
+ }
+ return super.call(receiver, arg1, arg2);
+ }
+ }
+}
diff --git a/src/main/java/org/codehaus/groovy/runtime/dgmimpl/arrays/ObjectArrayPutAtMetaMethod.java b/src/main/java/org/codehaus/groovy/runtime/dgmimpl/arrays/ObjectArrayPutAtMetaMethod.java
index 28e51ba..3db454d 100644
--- a/src/main/java/org/codehaus/groovy/runtime/dgmimpl/arrays/ObjectArrayPutAtMetaMethod.java
+++ b/src/main/java/org/codehaus/groovy/runtime/dgmimpl/arrays/ObjectArrayPutAtMetaMethod.java
@@ -1,97 +1,97 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.codehaus.groovy.runtime.dgmimpl.arrays;
-
-import groovy.lang.GString;
-import groovy.lang.MetaClassImpl;
-import groovy.lang.MetaMethod;
-import org.codehaus.groovy.reflection.CachedClass;
-import org.codehaus.groovy.reflection.ReflectionCache;
-import org.codehaus.groovy.runtime.callsite.CallSite;
-import org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite;
-import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
-
-public class ObjectArrayPutAtMetaMethod extends ArrayPutAtMetaMethod {
- private static final CachedClass OBJECT_CLASS = ReflectionCache.getCachedClass(Object.class);
- private static final CachedClass OBJECT_ARR_CLASS = ReflectionCache.OBJECT_ARRAY_CLASS;
- private static final CachedClass[] PARAM_CLASS_ARR = new CachedClass[]{INTEGER_CLASS, OBJECT_CLASS};
-
- public ObjectArrayPutAtMetaMethod() {
- parameterTypes = PARAM_CLASS_ARR;
- }
-
- public final CachedClass getDeclaringClass() {
- return OBJECT_ARR_CLASS;
- }
-
- public Object invoke(Object object, Object[] arguments) {
- final Object[] objects = (Object[]) object;
- final int index = normaliseIndex((Integer) arguments[0], objects.length);
- objects[index] = adjustNewValue(objects, arguments[1]);
- return null;
- }
-
- private static Object adjustNewValue(Object[] objects, Object newValue) {
- Class arrayComponentClass = objects.getClass().getComponentType();
- Object adjustedNewVal = newValue;
- if (newValue instanceof Number) {
- if (!arrayComponentClass.equals(newValue.getClass())) {
- adjustedNewVal = DefaultTypeTransformation.castToType(newValue, arrayComponentClass);
- }
- } else if (Character.class.isAssignableFrom(arrayComponentClass)) {
- adjustedNewVal = DefaultTypeTransformation.getCharFromSizeOneString(newValue);
- } else if (Number.class.isAssignableFrom(arrayComponentClass)) {
- if (newValue instanceof Character || newValue instanceof String || newValue instanceof GString) {
- Character ch = DefaultTypeTransformation.getCharFromSizeOneString(newValue);
- adjustedNewVal = DefaultTypeTransformation.castToType(ch, arrayComponentClass);
- }
- } else if (arrayComponentClass.isArray()) {
- adjustedNewVal = DefaultTypeTransformation.castToType(newValue, arrayComponentClass);
- }
- return adjustedNewVal;
- }
-
- public CallSite createPojoCallSite(CallSite site, MetaClassImpl metaClass, MetaMethod metaMethod, Class[] params, Object receiver, Object[] args) {
- if (!(args[0] instanceof Integer))
- return PojoMetaMethodSite.createNonAwareCallSite(site, metaClass, metaMethod, params, args);
- else
- return new MyPojoMetaMethodSite(site, metaClass, metaMethod, params);
- }
-
- private static class MyPojoMetaMethodSite extends PojoMetaMethodSite {
- public MyPojoMetaMethodSite(CallSite site, MetaClassImpl metaClass, MetaMethod metaMethod, Class[] params) {
- super(site, metaClass, metaMethod, params);
- }
-
- public Object call(Object receiver, Object arg1, Object arg2) throws Throwable {
- if (checkPojoMetaClass()) {
- try {
- final Object[] objects = (Object[]) receiver;
- objects[normaliseIndex((Integer) arg1, objects.length)] = adjustNewValue(objects, arg2);
- return null;
- }
- catch (ClassCastException e) {
- if ((receiver instanceof Object[]) && (arg1 instanceof Integer))
- throw e;
- }
- }
- return super.call(receiver, arg1, arg2);
- }
- }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.codehaus.groovy.runtime.dgmimpl.arrays;
+
+import groovy.lang.GString;
+import groovy.lang.MetaClassImpl;
+import groovy.lang.MetaMethod;
+import org.codehaus.groovy.reflection.CachedClass;
+import org.codehaus.groovy.reflection.ReflectionCache;
+import org.codehaus.groovy.runtime.callsite.CallSite;
+import org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite;
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+
+public class ObjectArrayPutAtMetaMethod extends ArrayPutAtMetaMethod {
+ private static final CachedClass OBJECT_CLASS = ReflectionCache.getCachedClass(Object.class);
+ private static final CachedClass OBJECT_ARR_CLASS = ReflectionCache.OBJECT_ARRAY_CLASS;
+ private static final CachedClass[] PARAM_CLASS_ARR = new CachedClass[]{INTEGER_CLASS, OBJECT_CLASS};
+
+ public ObjectArrayPutAtMetaMethod() {
+ parameterTypes = PARAM_CLASS_ARR;
+ }
+
+ public final CachedClass getDeclaringClass() {
+ return OBJECT_ARR_CLASS;
+ }
+
+ public Object invoke(Object object, Object[] arguments) {
+ final Object[] objects = (Object[]) object;
+ final int index = normaliseIndex((Integer) arguments[0], objects.length);
+ objects[index] = adjustNewValue(objects, arguments[1]);
+ return null;
+ }
+
+ private static Object adjustNewValue(Object[] objects, Object newValue) {
+ Class arrayComponentClass = objects.getClass().getComponentType();
+ Object adjustedNewVal = newValue;
+ if (newValue instanceof Number) {
+ if (!arrayComponentClass.equals(newValue.getClass())) {
+ adjustedNewVal = DefaultTypeTransformation.castToType(newValue, arrayComponentClass);
+ }
+ } else if (Character.class.isAssignableFrom(arrayComponentClass)) {
+ adjustedNewVal = DefaultTypeTransformation.getCharFromSizeOneString(newValue);
+ } else if (Number.class.isAssignableFrom(arrayComponentClass)) {
+ if (newValue instanceof Character || newValue instanceof String || newValue instanceof GString) {
+ Character ch = DefaultTypeTransformation.getCharFromSizeOneString(newValue);
+ adjustedNewVal = DefaultTypeTransformation.castToType(ch, arrayComponentClass);
+ }
+ } else if (arrayComponentClass.isArray()) {
+ adjustedNewVal = DefaultTypeTransformation.castToType(newValue, arrayComponentClass);
+ }
+ return adjustedNewVal;
+ }
+
+ public CallSite createPojoCallSite(CallSite site, MetaClassImpl metaClass, MetaMethod metaMethod, Class[] params, Object receiver, Object[] args) {
+ if (!(args[0] instanceof Integer))
+ return PojoMetaMethodSite.createNonAwareCallSite(site, metaClass, metaMethod, params, args);
+ else
+ return new MyPojoMetaMethodSite(site, metaClass, metaMethod, params);
+ }
+
+ private static class MyPojoMetaMethodSite extends PojoMetaMethodSite {
+ public MyPojoMetaMethodSite(CallSite site, MetaClassImpl metaClass, MetaMethod metaMethod, Class[] params) {
+ super(site, metaClass, metaMethod, params);
+ }
+
+ public Object call(Object receiver, Object arg1, Object arg2) throws Throwable {
+ if (checkPojoMetaClass()) {
+ try {
+ final Object[] objects = (Object[]) receiver;
+ objects[normaliseIndex((Integer) arg1, objects.length)] = adjustNewValue(objects, arg2);
+ return null;
+ }
+ catch (ClassCastException e) {
+ if ((receiver instanceof Object[]) && (arg1 instanceof Integer))
+ throw e;
+ }
+ }
+ return super.call(receiver, arg1, arg2);
+ }
+ }
+}
diff --git a/src/main/java/org/codehaus/groovy/runtime/metaclass/ConcurrentReaderHashMap.java b/src/main/java/org/codehaus/groovy/runtime/metaclass/ConcurrentReaderHashMap.java
index ef7da8f..560cf97 100644
--- a/src/main/java/org/codehaus/groovy/runtime/metaclass/ConcurrentReaderHashMap.java
+++ b/src/main/java/org/codehaus/groovy/runtime/metaclass/ConcurrentReaderHashMap.java
@@ -1,1271 +1,1271 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.codehaus.groovy.runtime.metaclass;
-
-import java.io.IOException;
-import java.io.Serializable;
-import java.util.AbstractCollection;
-import java.util.AbstractMap;
-import java.util.AbstractSet;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Enumeration;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.Set;
-
-/**
- * A hash table that supports mostly-concurrent reading, but
- * exclusive writing. Because reads are not limited to periods
- * without writes, a concurrent reader policy is weaker than a classic
- * reader/writer policy, but is generally faster and allows more
- * concurrency. This class is a good choice especially for tables that
- * are mainly created by one thread during the start-up phase of a
- * program, and from then on, are mainly read (with perhaps occasional
- * additions or removals) in many threads. If you also need concurrency
- * among writes, consider instead using ConcurrentHashMap.
- * <p>
- *
- * Successful retrievals using get(key) and containsKey(key) usually
- * run without locking. Unsuccessful ones (i.e., when the key is not
- * present) do involve brief synchronization (locking). Also, the
- * size and isEmpty methods are always synchronized.
- *
- * <p> Because retrieval operations can ordinarily overlap with
- * writing operations (i.e., put, remove, and their derivatives),
- * retrievals can only be guaranteed to return the results of the most
- * recently <em>completed</em> operations holding upon their
- * onset. Retrieval operations may or may not return results
- * reflecting in-progress writing operations. However, the retrieval
- * operations do always return consistent results -- either those
- * holding before any single modification or after it, but never a
- * nonsense result. For aggregate operations such as putAll and
- * clear, concurrent reads may reflect insertion or removal of only
- * some entries. In those rare contexts in which you use a hash table
- * to synchronize operations across threads (for example, to prevent
- * reads until after clears), you should either encase operations
- * in synchronized blocks, or instead use java.util.Hashtable.
- *
- * <p>
- *
- * This class also supports optional guaranteed
- * exclusive reads, simply by surrounding a call within a synchronized
- * block, as in <br>
- * <code>ConcurrentReaderHashMap t; ... Object v; <br>
- * synchronized(t) { v = t.get(k); } </code> <br>
- *
- * But this is not usually necessary in practice. For
- * example, it is generally inefficient to write:
- *
- * <pre>
- * ConcurrentReaderHashMap t; ... // Inefficient version
- * Object key; ...
- * Object value; ...
- * synchronized(t) {
- * if (!t.containsKey(key))
- * t.put(key, value);
- * // other code if not previously present
- * }
- * else {
- * // other code if it was previously present
- * }
- * }
- *</pre>
- * Instead, if the values are intended to be the same in each case, just take advantage of the fact that put returns
- * null if the key was not previously present:
- * <pre>
- * ConcurrentReaderHashMap t; ... // Use this instead
- * Object key; ...
- * Object value; ...
- * Object oldValue = t.put(key, value);
- * if (oldValue == null) {
- * // other code if not previously present
- * }
- * else {
- * // other code if it was previously present
- * }
- *</pre>
- * <p>
- *
- * Iterators and Enumerations (i.e., those returned by
- * keySet().iterator(), entrySet().iterator(), values().iterator(),
- * keys(), and elements()) return elements reflecting the state of the
- * hash table at some point at or since the creation of the
- * iterator/enumeration. They will return at most one instance of
- * each element (via next()/nextElement()), but might or might not
- * reflect puts and removes that have been processed since they were
- * created. They do <em>not</em> throw ConcurrentModificationException.
- * However, these iterators are designed to be used by only one
- * thread at a time. Sharing an iterator across multiple threads may
- * lead to unpredictable results if the table is being concurrently
- * modified. Again, you can ensure interference-free iteration by
- * enclosing the iteration in a synchronized block. <p>
- *
- * This class may be used as a direct replacement for any use of
- * java.util.Hashtable that does not depend on readers being blocked
- * during updates. Like Hashtable but unlike java.util.HashMap,
- * this class does NOT allow <tt>null</tt> to be used as a key or
- * value. This class is also typically faster than ConcurrentHashMap
- * when there is usually only one thread updating the table, but
- * possibly many retrieving values from it.
- * <p>
- *
- * Implementation note: A slightly faster implementation of
- * this class will be possible once planned Java Memory Model
- * revisions are in place.
- *
- * <p>[<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>]
- *
- * @author Adapted from ConcurrentHashMap (Doug Lea)
- * @author adapted by the Groovy community
- */
-public class ConcurrentReaderHashMap
- extends AbstractMap
- implements Cloneable, Serializable {
- private static final long serialVersionUID = -3225682440765612861L;
-
-
- /*
- The basic strategy is an optimistic-style scheme based on
- the guarantee that the hash table and its lists are always
- kept in a consistent enough state to be read without locking:
-
- * Read operations first proceed without locking, by traversing the
- apparently correct list of the apparently correct bin. If an
- entry is found, but not invalidated (value field null), it is
- returned. If not found, operations must recheck (after a memory
- barrier) to make sure they are using both the right list and
- the right table (which can change under re-sizes). If
- invalidated, reads must acquire main update lock to wait out
- the update, and then re-traverse.
-
- * All list additions are at the front of each bin, making it easy
- to check changes, and also fast to traverse. Entry next
- pointers are never assigned. Remove() builds new nodes when
- necessary to preserve this.
-
- * Remove() (also clear()) invalidates removed nodes to alert read
- operations that they must wait out the full modifications.
- */
-
- /** A Serializable class for barrier lock **/
- protected static class BarrierLock implements java.io.Serializable {
- private static final long serialVersionUID = -2159505361622844863L;
- }
-
- /**
- * Lock used only for its memory effects.
- **/
- protected final BarrierLock barrierLock = new BarrierLock();
-
- /**
- * field written to only to guarantee lock ordering.
- **/
- protected transient Object lastWrite;
-
- /**
- * Force a memory synchronization that will cause
- * all readers to see table. Call only when already
- * holding main sync lock.
- **/
- protected final void recordModification(Object x) {
- synchronized(barrierLock) {
- lastWrite = x;
- }
- }
-
- /**
- * Get ref to table; the reference and the cells it
- * accesses will be at least as fresh as from last
- * use of barrierLock
- **/
- protected final Entry[] getTableForReading() {
- synchronized(barrierLock) {
- return table;
- }
- }
-
-
- /**
- * The default initial number of table slots for this table (32).
- * Used when not otherwise specified in constructor.
- **/
- public static final int DEFAULT_INITIAL_CAPACITY = 32;
-
-
- /**
- * The minimum capacity, used if a lower value is implicitly specified
- * by either of the constructors with arguments.
- * MUST be a power of two.
- */
- private static final int MINIMUM_CAPACITY = 4;
-
- /**
- * The maximum capacity, used if a higher value is implicitly specified
- * by either of the constructors with arguments.
- * MUST be a power of two <= 1<<30.
- */
- private static final int MAXIMUM_CAPACITY = 1 << 30;
-
- /**
- * The default load factor for this table (1.0).
- * Used when not otherwise specified in constructor.
- **/
-
- public static final float DEFAULT_LOAD_FACTOR = 0.75f;
-
-
- /**
- * The hash table data.
- */
- protected transient Entry[] table;
-
- /**
- * The total number of mappings in the hash table.
- */
- protected transient int count;
-
- /**
- * The table is rehashed when its size exceeds this threshold. (The
- * value of this field is always (int)(capacity * loadFactor).)
- *
- * @serial
- */
- protected int threshold;
-
- /**
- * The load factor for the hash table.
- *
- * @serial
- */
- protected float loadFactor;
-
- /**
- * Returns the appropriate capacity (power of two) for the specified
- * initial capacity argument.
- */
- private static int p2capacity(int initialCapacity) {
- int cap = initialCapacity;
-
- // Compute the appropriate capacity
- int result;
- if (cap > MAXIMUM_CAPACITY || cap < 0) {
- result = MAXIMUM_CAPACITY;
- } else {
- result = MINIMUM_CAPACITY;
- while (result < cap)
- result <<= 1;
- }
- return result;
- }
-
- /**
- * Return hash code for Object x. Since we are using power-of-two
- * tables, it is worth the effort to improve hashcode via
- * the same multiplicative scheme as used in IdentityHashMap.
- */
- private static int hash(Object x) {
- int h = x.hashCode();
- // Multiply by 127 (quickly, via shifts), and mix in some high
- // bits to help guard against bunching of codes that are
- // consecutive or equally spaced.
- return ((h << 7) - h + (h >>> 9) + (h >>> 17));
- }
-
- /**
- * Check for equality of non-null references x and y.
- **/
- protected boolean eq(Object x, Object y) {
- return x == y || x.equals(y);
- }
-
- /**
- * Constructs a new, empty map with the specified initial
- * capacity and the specified load factor.
- *
- * @param initialCapacity the initial capacity
- * The actual initial capacity is rounded to the nearest power of two.
- * @param loadFactor the load factor of the ConcurrentReaderHashMap
- * @throws IllegalArgumentException if the initial maximum number
- * of elements is less
- * than zero, or if the load factor is non-positive.
- */
- public ConcurrentReaderHashMap(int initialCapacity, float loadFactor) {
- if (loadFactor <= 0)
- throw new IllegalArgumentException("Illegal Load factor: "+
- loadFactor);
- this.loadFactor = loadFactor;
-
- int cap = p2capacity(initialCapacity);
-
- table = new Entry[cap];
- threshold = (int)(cap * loadFactor);
- }
-
- /**
- * Constructs a new, empty map with the specified initial
- * capacity and default load factor.
- *
- * @param initialCapacity the initial capacity of the
- * ConcurrentReaderHashMap.
- * @throws IllegalArgumentException if the initial maximum number
- * of elements is less than zero.
- */
- public ConcurrentReaderHashMap(int initialCapacity) {
- this(initialCapacity, DEFAULT_LOAD_FACTOR);
- }
-
- /**
- * Constructs a new, empty map with a default initial capacity
- * and load factor.
- */
- public ConcurrentReaderHashMap() {
- this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
- }
-
- /**
- * Constructs a new map with the same mappings as the given map. The
- * map is created with a capacity of twice the number of mappings in
- * the given map or 16 (whichever is greater), and a default load factor.
- */
- public ConcurrentReaderHashMap(Map t) {
- this(Math.max((int) (t.size() / DEFAULT_LOAD_FACTOR) + 1, 16),
- DEFAULT_LOAD_FACTOR);
- putAll(t);
- }
-
- /**
- * Returns the number of key-value mappings in this map.
- *
- * @return the number of key-value mappings in this map.
- */
- public synchronized int size() {
- return count;
- }
-
- /**
- * Returns <tt>true</tt> if this map contains no key-value mappings.
- *
- * @return <tt>true</tt> if this map contains no key-value mappings.
- */
- public synchronized boolean isEmpty() {
- return count == 0;
- }
-
-
-
- /**
- * Returns the value to which the specified key is mapped in this table.
- *
- * @param key a key in the table.
- * @return the value to which the key is mapped in this table;
- * <code>null</code> if the key is not mapped to any value in
- * this table.
- * @exception NullPointerException if the key is <code>null</code>.
- * @see #put(Object, Object)
- */
- public Object get(Object key) {
-
- // throw null pointer exception if key null
- int hash = hash(key);
-
- /*
- Start off at the apparently correct bin. If entry is found, we
- need to check after a barrier anyway. If not found, we need a
- barrier to check if we are actually in right bin. So either
- way, we encounter only one barrier unless we need to retry.
- And we only need to fully synchronize if there have been
- concurrent modifications.
- */
-
- Entry[] tab = table;
- int index = hash & (tab.length - 1);
- Entry first = tab[index];
- Entry e = first;
-
- for (;;) {
- if (e == null) {
-
- // If key apparently not there, check to
- // make sure this was a valid read
-
- Entry[] reread = getTableForReading();
- if (tab == reread && first == tab[index])
- return null;
- else {
- // Wrong list -- must restart traversal at new first
- tab = reread;
- e = first = tab[index = hash & (tab.length-1)];
- }
-
- }
-
- else if (e.hash == hash && eq(key, e.key)) {
- Object value = e.value;
- if (value != null)
- return value;
-
- // Entry was invalidated during deletion. But it could
- // have been re-inserted, so we must re-traverse.
- // To avoid useless contention, get lock to wait out modifications
- // before re-traversing.
-
- synchronized(this) {
- tab = table;
- }
- e = first = tab[index = hash & (tab.length-1)];
-
- }
- else
- e = e.next;
- }
- }
-
-
- /**
- * Tests if the specified object is a key in this table.
- *
- * @param key possible key.
- * @return <code>true</code> if and only if the specified object
- * is a key in this table, as determined by the
- * <tt>equals</tt> method; <code>false</code> otherwise.
- * @exception NullPointerException if the key is <code>null</code>.
- * @see #contains(Object)
- */
- public boolean containsKey(Object key) {
- return get(key) != null;
- }
-
- /**
- * Maps the specified <code>key</code> to the specified
- * <code>value</code> in this table. Neither the key nor the
- * value can be <code>null</code>. <p>
- *
- * The value can be retrieved by calling the <code>get</code> method
- * with a key that is equal to the original key.
- *
- * @param key the table key.
- * @param value the value.
- * @return the previous value of the specified key in this table,
- * or <code>null</code> if it did not have one.
- * @exception NullPointerException if the key or value is <code>null</code>.
- * @see Object#equals(Object)
- * @see #get(Object)
- */
- public Object put(Object key, Object value) {
- if (value == null)
- throw new NullPointerException();
-
- int hash = hash(key);
- Entry[] tab = table;
- int index = hash & (tab.length-1);
- Entry first = tab[index];
- Entry e;
-
- for (e = first; e != null; e = e.next)
- if (e.hash == hash && eq(key, e.key))
- break;
-
- synchronized(this) {
- if (tab == table) {
- if (e == null) {
- // make sure we are adding to correct list
- if (first == tab[index]) {
- // Add to front of list
- Entry newEntry = new Entry(hash, key, value, first);
- tab[index] = newEntry;
- if (++count >= threshold) rehash();
- else recordModification(newEntry);
- return null;
- }
- }
- else {
- Object oldValue = e.value;
- if (first == tab[index] && oldValue != null) {
- e.value = value;
- return oldValue;
- }
- }
- }
-
- // retry if wrong list or lost race against concurrent remove
- return sput(key, value, hash);
- }
- }
-
-
- /**
- * Continuation of put(), called only when sync lock is
- * held and interference has been detected.
- **/
- protected Object sput(Object key, Object value, int hash) {
-
- Entry[] tab = table;
- int index = hash & (tab.length-1);
- Entry first = tab[index];
- Entry e = first;
-
- for (;;) {
- if (e == null) {
- Entry newEntry = new Entry(hash, key, value, first);
- tab[index] = newEntry;
- if (++count >= threshold) rehash();
- else recordModification(newEntry);
- return null;
- }
- else if (e.hash == hash && eq(key, e.key)) {
- Object oldValue = e.value;
- e.value = value;
- return oldValue;
- }
- else
- e = e.next;
- }
- }
-
-
- /**
- * Rehashes the contents of this map into a new table
- * with a larger capacity. This method is called automatically when the
- * number of keys in this map exceeds its capacity and load factor.
- */
- protected void rehash() {
- Entry[] oldTable = table;
- int oldCapacity = oldTable.length;
- if (oldCapacity >= MAXIMUM_CAPACITY) {
- threshold = Integer.MAX_VALUE; // avoid re-triggering
- return;
- }
-
- int newCapacity = oldCapacity << 1;
- int mask = newCapacity - 1;
- threshold = (int)(newCapacity * loadFactor);
-
- Entry[] newTable = new Entry[newCapacity];
- /*
- * Reclassify nodes in each list to new Map. Because we are
- * using power-of-two expansion, the elements from each bin
- * must either stay at same index, or move to
- * oldCapacity+index. We also eliminate unnecessary node
- * creation by catching cases where old nodes can be reused
- * because their next fields won't change. Statistically, at
- * the default threshold, only about one-sixth of them need
- * cloning. (The nodes they replace will be garbage
- * collectible as soon as they are no longer referenced by any
- * reader thread that may be in the midst of traversing table
- * right now.)
- */
-
- for (int i = 0; i < oldCapacity ; i++) {
- // We need to guarantee that any existing reads of old Map can
- // proceed. So we cannot yet null out each bin.
- Entry e = oldTable[i];
-
- if (e != null) {
- int idx = e.hash & mask;
- Entry next = e.next;
-
- // Single node on list
- if (next == null)
- newTable[idx] = e;
-
- else {
- // Reuse trailing consecutive sequence of all same bit
- Entry lastRun = e;
- int lastIdx = idx;
- for (Entry last = next; last != null; last = last.next) {
- int k = last.hash & mask;
- if (k != lastIdx) {
- lastIdx = k;
- lastRun = last;
- }
- }
- newTable[lastIdx] = lastRun;
-
- // Clone all remaining nodes
- for (Entry p = e; p != lastRun; p = p.next) {
- int k = p.hash & mask;
- newTable[k] = new Entry(p.hash, p.key,
- p.value, newTable[k]);
- }
- }
- }
- }
-
- table = newTable;
- recordModification(newTable);
- }
-
- /**
- * Removes the key (and its corresponding value) from this
- * table. This method does nothing if the key is not in the table.
- *
- * @param key the key that needs to be removed.
- * @return the value to which the key had been mapped in this table,
- * or <code>null</code> if the key did not have a mapping.
- * @exception NullPointerException if the key is
- * <code>null</code>.
- */
- public Object remove(Object key) {
- /*
- Find the entry, then
- 1. Set value field to null, to force get() to retry
- 2. Rebuild the list without this entry.
- All entries following removed node can stay in list, but
- all preceding ones need to be cloned. Traversals rely
- on this strategy to ensure that elements will not be
- repeated during iteration.
- */
-
-
- int hash = hash(key);
- Entry[] tab = table;
- int index = hash & (tab.length-1);
- Entry first = tab[index];
- Entry e = first;
-
- for (e = first; e != null; e = e.next)
- if (e.hash == hash && eq(key, e.key))
- break;
-
-
- synchronized(this) {
- if (tab == table) {
- if (e == null) {
- if (first == tab[index])
- return null;
- }
- else {
- Object oldValue = e.value;
- if (first == tab[index] && oldValue != null) {
- e.value = null;
- count--;
-
- Entry head = e.next;
- for (Entry p = first; p != e; p = p.next)
- head = new Entry(p.hash, p.key, p.value, head);
-
- tab[index] = head;
- recordModification(head);
- return oldValue;
- }
- }
- }
-
- // Wrong list or interference
- return sremove(key, hash);
- }
- }
-
- /**
- * Continuation of remove(), called only when sync lock is
- * held and interference has been detected.
- **/
- protected Object sremove(Object key, int hash) {
- Entry[] tab = table;
- int index = hash & (tab.length-1);
- Entry first = tab[index];
-
- for (Entry e = first; e != null; e = e.next) {
- if (e.hash == hash && eq(key, e.key)) {
- Object oldValue = e.value;
- e.value = null;
- count--;
- Entry head = e.next;
- for (Entry p = first; p != e; p = p.next)
- head = new Entry(p.hash, p.key, p.value, head);
-
- tab[index] = head;
- recordModification(head);
- return oldValue;
- }
- }
- return null;
- }
-
-
- /**
- * Returns <tt>true</tt> if this map maps one or more keys to the
- * specified value. Note: This method requires a full internal
- * traversal of the hash table, and so is much slower than
- * method <tt>containsKey</tt>.
- *
- * @param value value whose presence in this map is to be tested.
- * @return <tt>true</tt> if this map maps one or more keys to the
- * specified value.
- * @exception NullPointerException if the value is <code>null</code>.
- */
- public boolean containsValue(Object value) {
- if (value == null) throw new NullPointerException();
-
- Entry tab[] = getTableForReading();
-
- for (int i = 0 ; i < tab.length; ++i) {
- for (Entry e = tab[i] ; e != null ; e = e.next)
- if (value.equals(e.value))
- return true;
- }
-
- return false;
- }
-
- /**
- * Tests if some key maps into the specified value in this table.
- * This operation is more expensive than the <code>containsKey</code>
- * method.<p>
- *
- * Note that this method is identical in functionality to containsValue,
- * (which is part of the Map interface in the collections framework).
- *
- * @param value a value to search for.
- * @return <code>true</code> if and only if some key maps to the
- * <code>value</code> argument in this table as
- * determined by the <tt>equals</tt> method;
- * <code>false</code> otherwise.
- * @exception NullPointerException if the value is <code>null</code>.
- * @see #containsKey(Object)
- * @see #containsValue(Object)
- * @see Map
- */
- public boolean contains(Object value) {
- return containsValue(value);
- }
-
-
- /**
- * Copies all of the mappings from the specified map to this one.
- *
- * These mappings replace any mappings that this map had for any of the
- * keys currently in the specified Map.
- *
- * @param t Mappings to be stored in this map.
- */
- public synchronized void putAll(Map t) {
- int n = t.size();
- if (n == 0)
- return;
-
- // Expand enough to hold at least n elements without resizing.
- // We can only resize table by factor of two at a time.
- // It is faster to rehash with fewer elements, so do it now.
- while (n >= threshold)
- rehash();
-
- for (Iterator it = t.entrySet().iterator(); it.hasNext();) {
- Map.Entry entry = (Map.Entry) it.next();
- Object key = entry.getKey();
- Object value = entry.getValue();
- put(key, value);
- }
- }
-
-
- /**
- * Removes all mappings from this map.
- */
- public synchronized void clear() {
- Entry tab[] = table;
- for (int i = 0; i < tab.length ; ++i) {
-
- // must invalidate all to force concurrent get's to wait and then retry
- for (Entry e = tab[i]; e != null; e = e.next)
- e.value = null;
-
- tab[i] = null;
- }
- count = 0;
- recordModification(tab);
- }
-
- /**
- * Returns a shallow copy of this
- * <tt>ConcurrentReaderHashMap</tt> instance: the keys and
- * values themselves are not cloned.
- *
- * @return a shallow copy of this map.
- */
- public synchronized Object clone() {
- try {
- ConcurrentReaderHashMap t = (ConcurrentReaderHashMap)super.clone();
-
- t.keySet = null;
- t.entrySet = null;
- t.values = null;
-
- Entry[] tab = table;
- t.table = new Entry[tab.length];
- Entry[] ttab = t.table;
-
- for (int i = 0; i < tab.length; ++i) {
- Entry first = null;
- for (Entry e = tab[i]; e != null; e = e.next)
- first = new Entry(e.hash, e.key, e.value, first);
- ttab[i] = first;
- }
-
- return t;
- }
- catch (CloneNotSupportedException e) {
- // this shouldn't happen, since we are Cloneable
- throw new InternalError();
- }
- }
-
- // Views
-
- protected transient Set keySet = null;
- protected transient Set entrySet = null;
- protected transient Collection values = null;
-
- /**
- * Returns a set view of the keys contained in this map. The set is
- * backed by the map, so changes to the map are reflected in the set, and
- * vice-versa. The set supports element removal, which removes the
- * corresponding mapping from this map, via the <tt>Iterator.remove</tt>,
- * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt>, and
- * <tt>clear</tt> operations. It does not support the <tt>add</tt> or
- * <tt>addAll</tt> operations.
- *
- * @return a set view of the keys contained in this map.
- */
- public Set keySet() {
- Set ks = keySet;
- return (ks != null)? ks : (keySet = new KeySet());
- }
-
- private class KeySet extends AbstractSet {
- public Iterator iterator() {
- return new KeyIterator();
- }
- public int size() {
- return ConcurrentReaderHashMap.this.size();
- }
- public boolean contains(Object o) {
- return ConcurrentReaderHashMap.this.containsKey(o);
- }
- public boolean remove(Object o) {
- return ConcurrentReaderHashMap.this.remove(o) != null;
- }
- public void clear() {
- ConcurrentReaderHashMap.this.clear();
- }
- public Object[] toArray() {
- Collection c = new ArrayList();
- for (Iterator i = iterator(); i.hasNext(); )
- c.add(i.next());
- return c.toArray();
- }
- public Object[] toArray(Object[] a) {
- Collection c = new ArrayList();
- for (Iterator i = iterator(); i.hasNext(); )
- c.add(i.next());
- return c.toArray(a);
- }
- }
-
- /**
- * Returns a collection view of the values contained in this map. The
- * collection is backed by the map, so changes to the map are reflected in
- * the collection, and vice-versa. The collection supports element
- * removal, which removes the corresponding mapping from this map, via the
- * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,
- * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> operations.
- * It does not support the <tt>add</tt> or <tt>addAll</tt> operations.
- *
- * @return a collection view of the values contained in this map.
- */
- public Collection values() {
- Collection vs = values;
- return (vs != null)? vs : (values = new Values());
- }
-
- private class Values extends AbstractCollection {
- public Iterator iterator() {
- return new ValueIterator();
- }
- public int size() {
- return ConcurrentReaderHashMap.this.size();
- }
- public boolean contains(Object o) {
- return ConcurrentReaderHashMap.this.containsValue(o);
- }
- public void clear() {
- ConcurrentReaderHashMap.this.clear();
- }
- public Object[] toArray() {
- Collection c = new ArrayList();
- for (Iterator i = iterator(); i.hasNext(); )
- c.add(i.next());
- return c.toArray();
- }
- public Object[] toArray(Object[] a) {
- Collection c = new ArrayList();
- for (Iterator i = iterator(); i.hasNext(); )
- c.add(i.next());
- return c.toArray(a);
- }
- }
-
- /**
- * Returns a collection view of the mappings contained in this map. Each
- * element in the returned collection is a <tt>Map.Entry</tt>. The
- * collection is backed by the map, so changes to the map are reflected in
- * the collection, and vice-versa. The collection supports element
- * removal, which removes the corresponding mapping from the map, via the
- * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,
- * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> operations.
- * It does not support the <tt>add</tt> or <tt>addAll</tt> operations.
- *
- * @return a collection view of the mappings contained in this map.
- */
- public Set entrySet() {
- Set es = entrySet;
- return (es != null) ? es : (entrySet = new EntrySet());
- }
-
- private class EntrySet extends AbstractSet {
- public Iterator iterator() {
- return new HashIterator();
- }
- public boolean contains(Object o) {
- if (!(o instanceof Map.Entry))
- return false;
- Map.Entry entry = (Map.Entry)o;
- Object v = ConcurrentReaderHashMap.this.get(entry.getKey());
- return v != null && v.equals(entry.getValue());
- }
- public boolean remove(Object o) {
- if (!(o instanceof Map.Entry))
- return false;
- return ConcurrentReaderHashMap.this.findAndRemoveEntry((Map.Entry)o);
- }
- public int size() {
- return ConcurrentReaderHashMap.this.size();
- }
- public void clear() {
- ConcurrentReaderHashMap.this.clear();
- }
- public Object[] toArray() {
- Collection c = new ArrayList();
- for (Iterator i = iterator(); i.hasNext(); )
- c.add(i.next());
- return c.toArray();
- }
- public Object[] toArray(Object[] a) {
- Collection c = new ArrayList();
- for (Iterator i = iterator(); i.hasNext(); )
- c.add(i.next());
- return c.toArray(a);
- }
- }
-
- /**
- * Helper method for entrySet.remove
- **/
- protected synchronized boolean findAndRemoveEntry(Map.Entry entry) {
- Object key = entry.getKey();
- Object v = get(key);
- if (v != null && v.equals(entry.getValue())) {
- remove(key);
- return true;
- }
- else
- return false;
- }
-
- /**
- * Returns an enumeration of the keys in this table.
- *
- * @return an enumeration of the keys in this table.
- * @see Enumeration
- * @see #elements()
- * @see #keySet()
- * @see Map
- */
- public Enumeration keys() {
- return new KeyIterator();
- }
-
- /**
- * Returns an enumeration of the values in this table.
- * Use the Enumeration methods on the returned object to fetch the elements
- * sequentially.
- *
- * @return an enumeration of the values in this table.
- * @see java.util.Enumeration
- * @see #keys()
- * @see #values()
- * @see Map
- */
- public Enumeration elements() {
- return new ValueIterator();
- }
-
-
- /**
- * ConcurrentReaderHashMap collision list entry.
- */
- protected static class Entry implements Map.Entry {
-
- /*
- The use of volatile for value field ensures that
- we can detect status changes without synchronization.
- The other fields are never changed, and are
- marked as final.
- */
- protected final int hash;
- protected final Object key;
- protected final Entry next;
- protected volatile Object value;
-
- Entry(int hash, Object key, Object value, Entry next) {
- this.hash = hash;
- this.key = key;
- this.next = next;
- this.value = value;
- }
-
- // Map.Entry Ops
-
- public Object getKey() {
- return key;
- }
-
- /**
- * Get the value. Note: In an entrySet or entrySet.iterator,
- * unless the set or iterator is used under synchronization of the
- * table as a whole (or you can otherwise guarantee lack of
- * concurrent modification), <tt>getValue</tt> <em>might</em>
- * return null, reflecting the fact that the entry has been
- * concurrently removed. However, there are no assurances that
- * concurrent removals will be reflected using this method.
- *
- * @return the current value, or null if the entry has been
- * detectably removed.
- **/
- public Object getValue() {
- return value;
- }
-
- /**
- * Set the value of this entry. Note: In an entrySet or
- * entrySet.iterator), unless the set or iterator is used under
- * synchronization of the table as a whole (or you can otherwise
- * guarantee lack of concurrent modification), <tt>setValue</tt>
- * is not strictly guaranteed to actually replace the value field
- * obtained via the <tt>get</tt> operation of the underlying hash
- * table in multi-threaded applications. If iterator-wide
- * synchronization is not used, and any other concurrent
- * <tt>put</tt> or <tt>remove</tt> operations occur, sometimes
- * even to <em>other</em> entries, then this change is not
- * guaranteed to be reflected in the hash table. (It might, or it
- * might not. There are no assurances either way.)
- *
- * @param value the new value.
- * @return the previous value, or null if entry has been detectably
- * removed.
- * @exception NullPointerException if the value is <code>null</code>.
- *
- **/
- public Object setValue(Object value) {
- if (value == null)
- throw new NullPointerException();
- Object oldValue = this.value;
- this.value = value;
- return oldValue;
- }
-
- public boolean equals(Object o) {
- if (!(o instanceof Map.Entry))
- return false;
- Map.Entry e = (Map.Entry)o;
- return (key.equals(e.getKey()) && value.equals(e.getValue()));
- }
-
- public int hashCode() {
- return key.hashCode() ^ value.hashCode();
- }
-
- public String toString() {
- return key + "=" + value;
- }
-
- }
-
- protected class HashIterator implements Iterator, Enumeration {
- protected final Entry[] tab; // snapshot of table
- protected int index; // current slot
- protected Entry entry = null; // current node of slot
- protected Object currentKey; // key for current node
- protected Object currentValue; // value for current node
- protected Entry lastReturned = null; // last node returned by next
-
- protected HashIterator() {
- tab = ConcurrentReaderHashMap.this.getTableForReading();
- index = tab.length - 1;
- }
-
- public boolean hasMoreElements() { return hasNext(); }
- public Object nextElement() { return next(); }
-
-
- public boolean hasNext() {
-
- /*
- currentKey and currentValue are set here to ensure that next()
- returns normally if hasNext() returns true. This avoids
- surprises especially when final element is removed during
- traversal -- instead, we just ignore the removal during
- current traversal.
- */
-
- for (;;) {
- if (entry != null) {
- Object v = entry.value;
- if (v != null) {
- currentKey = entry.key;
- currentValue = v;
- return true;
- }
- else
- entry = entry.next;
- }
-
- while (entry == null && index >= 0)
- entry = tab[index--];
-
- if (entry == null) {
- currentKey = currentValue = null;
- return false;
- }
- }
- }
-
- protected Object returnValueOfNext() { return entry; }
-
- public Object next() {
- if (currentKey == null && !hasNext())
- throw new NoSuchElementException();
-
- Object result = returnValueOfNext();
- lastReturned = entry;
- currentKey = currentValue = null;
- entry = entry.next;
- return result;
- }
-
- public void remove() {
- if (lastReturned == null)
- throw new IllegalStateException();
- ConcurrentReaderHashMap.this.remove(lastReturned.key);
- lastReturned = null;
- }
-
- }
-
-
- protected class KeyIterator extends HashIterator {
- protected Object returnValueOfNext() { return currentKey; }
- }
-
- protected class ValueIterator extends HashIterator {
- protected Object returnValueOfNext() { return currentValue; }
- }
-
-
-
- /**
- * Save the state of the <tt>ConcurrentReaderHashMap</tt>
- * instance to a stream (i.e.,
- * serialize it).
- *
- * @param s the stream
- * @serialData The <i>capacity</i> of the
- * ConcurrentReaderHashMap (the length of the
- * bucket array) is emitted (int), followed by the
- * <i>size</i> of the ConcurrentReaderHashMap (the number of key-value
- * mappings), followed by the key (Object) and value (Object)
- * for each key-value mapping represented by the ConcurrentReaderHashMap
- * The key-value mappings are emitted in no particular order.
- */
- private synchronized void writeObject(java.io.ObjectOutputStream s)
- throws IOException {
- // Write out the threshold, loadfactor, and any hidden stuff
- s.defaultWriteObject();
-
- // Write out number of buckets
- s.writeInt(table.length);
-
- // Write out size (number of Mappings)
- s.writeInt(count);
-
- // Write out keys and values (alternating)
- for (int index = table.length-1; index >= 0; index--) {
- Entry entry = table[index];
-
- while (entry != null) {
- s.writeObject(entry.key);
- s.writeObject(entry.value);
- entry = entry.next;
- }
- }
- }
-
- /**
- * Reconstitute the <tt>ConcurrentReaderHashMap</tt>
- * instance from a stream (i.e.,
- * deserialize it).
- *
- * @param s the stream
- */
- private synchronized void readObject(java.io.ObjectInputStream s)
- throws IOException, ClassNotFoundException {
- // Read in the threshold, loadfactor, and any hidden stuff
- s.defaultReadObject();
-
- // Read in number of buckets and allocate the bucket array;
- int numBuckets = s.readInt();
- table = new Entry[numBuckets];
-
- // Read in size (number of Mappings)
- int size = s.readInt();
-
- // Read the keys and values, and put the mappings in the table
- for (int i=0; i<size; i++) {
- Object key = s.readObject();
- Object value = s.readObject();
- put(key, value);
- }
- }
-
- /**
- * @return the number of slots in this table
- **/
- public synchronized int capacity() {
- return table.length;
- }
-
- /**
- * @return the load factor
- **/
- public float loadFactor() {
- return loadFactor;
- }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.codehaus.groovy.runtime.metaclass;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.AbstractCollection;
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+/**
+ * A hash table that supports mostly-concurrent reading, but
+ * exclusive writing. Because reads are not limited to periods
+ * without writes, a concurrent reader policy is weaker than a classic
+ * reader/writer policy, but is generally faster and allows more
+ * concurrency. This class is a good choice especially for tables that
+ * are mainly created by one thread during the start-up phase of a
+ * program, and from then on, are mainly read (with perhaps occasional
+ * additions or removals) in many threads. If you also need concurrency
+ * among writes, consider instead using ConcurrentHashMap.
+ * <p>
+ *
+ * Successful retrievals using get(key) and containsKey(key) usually
+ * run without locking. Unsuccessful ones (i.e., when the key is not
+ * present) do involve brief synchronization (locking). Also, the
+ * size and isEmpty methods are always synchronized.
+ *
+ * <p> Because retrieval operations can ordinarily overlap with
+ * writing operations (i.e., put, remove, and their derivatives),
+ * retrievals can only be guaranteed to return the results of the most
+ * recently <em>completed</em> operations holding upon their
+ * onset. Retrieval operations may or may not return results
+ * reflecting in-progress writing operations. However, the retrieval
+ * operations do always return consistent results -- either those
+ * holding before any single modification or after it, but never a
+ * nonsense result. For aggregate operations such as putAll and
+ * clear, concurrent reads may reflect insertion or removal of only
+ * some entries. In those rare contexts in which you use a hash table
+ * to synchronize operations across threads (for example, to prevent
+ * reads until after clears), you should either encase operations
+ * in synchronized blocks, or instead use java.util.Hashtable.
+ *
+ * <p>
+ *
+ * This class also supports optional guaranteed
+ * exclusive reads, simply by surrounding a call within a synchronized
+ * block, as in <br>
+ * <code>ConcurrentReaderHashMap t; ... Object v; <br>
+ * synchronized(t) { v = t.get(k); } </code> <br>
+ *
+ * But this is not usually necessary in practice. For
+ * example, it is generally inefficient to write:
+ *
+ * <pre>
+ * ConcurrentReaderHashMap t; ... // Inefficient version
+ * Object key; ...
+ * Object value; ...
+ * synchronized(t) {
+ * if (!t.containsKey(key))
+ * t.put(key, value);
+ * // other code if not previously present
+ * }
+ * else {
+ * // other code if it was previously present
+ * }
+ * }
+ *</pre>
+ * Instead, if the values are intended to be the same in each case, just take advantage of the fact that put returns
+ * null if the key was not previously present:
+ * <pre>
+ * ConcurrentReaderHashMap t; ... // Use this instead
+ * Object key; ...
+ * Object value; ...
+ * Object oldValue = t.put(key, value);
+ * if (oldValue == null) {
+ * // other code if not previously present
+ * }
+ * else {
+ * // other code if it was previously present
+ * }
+ *</pre>
+ * <p>
+ *
+ * Iterators and Enumerations (i.e., those returned by
+ * keySet().iterator(), entrySet().iterator(), values().iterator(),
+ * keys(), and elements()) return elements reflecting the state of the
+ * hash table at some point at or since the creation of the
+ * iterator/enumeration. They will return at most one instance of
+ * each element (via next()/nextElement()), but might or might not
+ * reflect puts and removes that have been processed since they were
+ * created. They do <em>not</em> throw ConcurrentModificationException.
+ * However, these iterators are designed to be used by only one
+ * thread at a time. Sharing an iterator across multiple threads may
+ * lead to unpredictable results if the table is being concurrently
+ * modified. Again, you can ensure interference-free iteration by
+ * enclosing the iteration in a synchronized block. <p>
+ *
+ * This class may be used as a direct replacement for any use of
+ * java.util.Hashtable that does not depend on readers being blocked
+ * during updates. Like Hashtable but unlike java.util.HashMap,
+ * this class does NOT allow <tt>null</tt> to be used as a key or
+ * value. This class is also typically faster than ConcurrentHashMap
+ * when there is usually only one thread updating the table, but
+ * possibly many retrieving values from it.
+ * <p>
+ *
+ * Implementation note: A slightly faster implementation of
+ * this class will be possible once planned Java Memory Model
+ * revisions are in place.
+ *
+ * <p>[<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>]
+ *
+ * @author Adapted from ConcurrentHashMap (Doug Lea)
+ * @author adapted by the Groovy community
+ */
+public class ConcurrentReaderHashMap
+ extends AbstractMap
+ implements Cloneable, Serializable {
+ private static final long serialVersionUID = -3225682440765612861L;
+
+
+ /*
+ The basic strategy is an optimistic-style scheme based on
+ the guarantee that the hash table and its lists are always
+ kept in a consistent enough state to be read without locking:
+
+ * Read operations first proceed without locking, by traversing the
+ apparently correct list of the apparently correct bin. If an
+ entry is found, but not invalidated (value field null), it is
+ returned. If not found, operations must recheck (after a memory
+ barrier) to make sure they are using both the right list and
+ the right table (which can change under re-sizes). If
+ invalidated, reads must acquire main update lock to wait out
+ the update, and then re-traverse.
+
+ * All list additions are at the front of each bin, making it easy
+ to check changes, and also fast to traverse. Entry next
+ pointers are never assigned. Remove() builds new nodes when
+ necessary to preserve this.
+
+ * Remove() (also clear()) invalidates removed nodes to alert read
+ operations that they must wait out the full modifications.
+ */
+
+ /** A Serializable class for barrier lock **/
+ protected static class BarrierLock implements java.io.Serializable {
+ private static final long serialVersionUID = -2159505361622844863L;
+ }
+
+ /**
+ * Lock used only for its memory effects.
+ **/
+ protected final BarrierLock barrierLock = new BarrierLock();
+
+ /**
+ * field written to only to guarantee lock ordering.
+ **/
+ protected transient Object lastWrite;
+
+ /**
+ * Force a memory synchronization that will cause
+ * all readers to see table. Call only when already
+ * holding main sync lock.
+ **/
+ protected final void recordModification(Object x) {
+ synchronized(barrierLock) {
+ lastWrite = x;
+ }
+ }
+
+ /**
+ * Get ref to table; the reference and the cells it
+ * accesses will be at least as fresh as from last
+ * use of barrierLock
+ **/
+ protected final Entry[] getTableForReading() {
+ synchronized(barrierLock) {
+ return table;
+ }
+ }
+
+
+ /**
+ * The default initial number of table slots for this table (32).
+ * Used when not otherwise specified in constructor.
+ **/
+ public static final int DEFAULT_INITIAL_CAPACITY = 32;
+
+
+ /**
+ * The minimum capacity, used if a lower value is implicitly specified
+ * by either of the constructors with arguments.
+ * MUST be a power of two.
+ */
+ private static final int MINIMUM_CAPACITY = 4;
+
+ /**
+ * The maximum capacity, used if a higher value is implicitly specified
+ * by either of the constructors with arguments.
+ * MUST be a power of two <= 1<<30.
+ */
+ private static final int MAXIMUM_CAPACITY = 1 << 30;
+
+ /**
+ * The default load factor for this table (1.0).
+ * Used when not otherwise specified in constructor.
+ **/
+
+ public static final float DEFAULT_LOAD_FACTOR = 0.75f;
+
+
+ /**
+ * The hash table data.
+ */
+ protected transient Entry[] table;
+
+ /**
+ * The total number of mappings in the hash table.
+ */
+ protected transient int count;
+
+ /**
+ * The table is rehashed when its size exceeds this threshold. (The
+ * value of this field is always (int)(capacity * loadFactor).)
+ *
+ * @serial
+ */
+ protected int threshold;
+
+ /**
+ * The load factor for the hash table.
+ *
+ * @serial
+ */
+ protected float loadFactor;
+
+ /**
+ * Returns the appropriate capacity (power of two) for the specified
+ * initial capacity argument.
+ */
+ private static int p2capacity(int initialCapacity) {
+ int cap = initialCapacity;
+
+ // Compute the appropriate capacity
+ int result;
+ if (cap > MAXIMUM_CAPACITY || cap < 0) {
+ result = MAXIMUM_CAPACITY;
+ } else {
+ result = MINIMUM_CAPACITY;
+ while (result < cap)
+ result <<= 1;
+ }
+ return result;
+ }
+
+ /**
+ * Return hash code for Object x. Since we are using power-of-two
+ * tables, it is worth the effort to improve hashcode via
+ * the same multiplicative scheme as used in IdentityHashMap.
+ */
+ private static int hash(Object x) {
+ int h = x.hashCode();
+ // Multiply by 127 (quickly, via shifts), and mix in some high
+ // bits to help guard against bunching of codes that are
+ // consecutive or equally spaced.
+ return ((h << 7) - h + (h >>> 9) + (h >>> 17));
+ }
+
+ /**
+ * Check for equality of non-null references x and y.
+ **/
+ protected boolean eq(Object x, Object y) {
+ return x == y || x.equals(y);
+ }
+
+ /**
+ * Constructs a new, empty map with the specified initial
+ * capacity and the specified load factor.
+ *
+ * @param initialCapacity the initial capacity
+ * The actual initial capacity is rounded to the nearest power of two.
+ * @param loadFactor the load factor of the ConcurrentReaderHashMap
+ * @throws IllegalArgumentException if the initial maximum number
+ * of elements is less
+ * than zero, or if the load factor is non-positive.
+ */
+ public ConcurrentReaderHashMap(int initialCapacity, float loadFactor) {
+ if (loadFactor <= 0)
+ throw new IllegalArgumentException("Illegal Load factor: "+
+ loadFactor);
+ this.loadFactor = loadFactor;
+
+ int cap = p2capacity(initialCapacity);
+
+ table = new Entry[cap];
+ threshold = (int)(cap * loadFactor);
+ }
+
+ /**
+ * Constructs a new, empty map with the specified initial
+ * capacity and default load factor.
+ *
+ * @param initialCapacity the initial capacity of the
+ * ConcurrentReaderHashMap.
+ * @throws IllegalArgumentException if the initial maximum number
+ * of elements is less than zero.
+ */
+ public ConcurrentReaderHashMap(int initialCapacity) {
+ this(initialCapacity, DEFAULT_LOAD_FACTOR);
+ }
+
+ /**
+ * Constructs a new, empty map with a default initial capacity
+ * and load factor.
+ */
+ public ConcurrentReaderHashMap() {
+ this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
+ }
+
+ /**
+ * Constructs a new map with the same mappings as the given map. The
+ * map is created with a capacity of twice the number of mappings in
+ * the given map or 16 (whichever is greater), and a default load factor.
+ */
+ public ConcurrentReaderHashMap(Map t) {
+ this(Math.max((int) (t.size() / DEFAULT_LOAD_FACTOR) + 1, 16),
+ DEFAULT_LOAD_FACTOR);
+ putAll(t);
+ }
+
+ /**
+ * Returns the number of key-value mappings in this map.
+ *
+ * @return the number of key-value mappings in this map.
+ */
+ public synchronized int size() {
+ return count;
+ }
+
+ /**
+ * Returns <tt>true</tt> if this map contains no key-value mappings.
+ *
+ * @return <tt>true</tt> if this map contains no key-value mappings.
+ */
+ public synchronized boolean isEmpty() {
+ return count == 0;
+ }
+
+
+
+ /**
+ * Returns the value to which the specified key is mapped in this table.
+ *
+ * @param key a key in the table.
+ * @return the value to which the key is mapped in this table;
+ * <code>null</code> if the key is not mapped to any value in
+ * this table.
+ * @exception NullPointerException if the key is <code>null</code>.
+ * @see #put(Object, Object)
+ */
+ public Object get(Object key) {
+
+ // throw null pointer exception if key null
+ int hash = hash(key);
+
+ /*
+ Start off at the apparently correct bin. If entry is found, we
+ need to check after a barrier anyway. If not found, we need a
+ barrier to check if we are actually in right bin. So either
+ way, we encounter only one barrier unless we need to retry.
+ And we only need to fully synchronize if there have been
+ concurrent modifications.
+ */
+
+ Entry[] tab = table;
+ int index = hash & (tab.length - 1);
+ Entry first = tab[index];
+ Entry e = first;
+
+ for (;;) {
+ if (e == null) {
+
+ // If key apparently not there, check to
+ // make sure this was a valid read
+
+ Entry[] reread = getTableForReading();
+ if (tab == reread && first == tab[index])
+ return null;
+ else {
+ // Wrong list -- must restart traversal at new first
+ tab = reread;
+ e = first = tab[index = hash & (tab.length-1)];
+ }
+
+ }
+
+ else if (e.hash == hash && eq(key, e.key)) {
+ Object value = e.value;
+ if (value != null)
+ return value;
+
+ // Entry was invalidated during deletion. But it could
+ // have been re-inserted, so we must re-traverse.
+ // To avoid useless contention, get lock to wait out modifications
+ // before re-traversing.
+
+ synchronized(this) {
+ tab = table;
+ }
+ e = first = tab[index = hash & (tab.length-1)];
+
+ }
+ else
+ e = e.next;
+ }
+ }
+
+
+ /**
+ * Tests if the specified object is a key in this table.
+ *
+ * @param key possible key.
+ * @return <code>true</code> if and only if the specified object
+ * is a key in this table, as determined by the
+ * <tt>equals</tt> method; <code>false</code> otherwise.
+ * @exception NullPointerException if the key is <code>null</code>.
+ * @see #contains(Object)
+ */
+ public boolean containsKey(Object key) {
+ return get(key) != null;
+ }
+
+ /**
+ * Maps the specified <code>key</code> to the specified
+ * <code>value</code> in this table. Neither the key nor the
+ * value can be <code>null</code>. <p>
+ *
+ * The value can be retrieved by calling the <code>get</code> method
+ * with a key that is equal to the original key.
+ *
+ * @param key the table key.
+ * @param value the value.
+ * @return the previous value of the specified key in this table,
+ * or <code>null</code> if it did not have one.
+ * @exception NullPointerException if the key or value is <code>null</code>.
+ * @see Object#equals(Object)
+ * @see #get(Object)
+ */
+ public Object put(Object key, Object value) {
+ if (value == null)
+ throw new NullPointerException();
+
+ int hash = hash(key);
+ Entry[] tab = table;
+ int index = hash & (tab.length-1);
+ Entry first = tab[index];
+ Entry e;
+
+ for (e = first; e != null; e = e.next)
+ if (e.hash == hash && eq(key, e.key))
+ break;
+
+ synchronized(this) {
+ if (tab == table) {
+ if (e == null) {
+ // make sure we are adding to correct list
+ if (first == tab[index]) {
+ // Add to front of list
+ Entry newEntry = new Entry(hash, key, value, first);
+ tab[index] = newEntry;
+ if (++count >= threshold) rehash();
+ else recordModification(newEntry);
+ return null;
+ }
+ }
+ else {
+ Object oldValue = e.value;
+ if (first == tab[index] && oldValue != null) {
+ e.value = value;
+ return oldValue;
+ }
+ }
+ }
+
+ // retry if wrong list or lost race against concurrent remove
+ return sput(key, value, hash);
+ }
+ }
+
+
+ /**
+ * Continuation of put(), called only when sync lock is
+ * held and interference has been detected.
+ **/
+ protected Object sput(Object key, Object value, int hash) {
+
+ Entry[] tab = table;
+ int index = hash & (tab.length-1);
+ Entry first = tab[index];
+ Entry e = first;
+
+ for (;;) {
+ if (e == null) {
+ Entry newEntry = new Entry(hash, key, value, first);
+ tab[index] = newEntry;
+ if (++count >= threshold) rehash();
+ else recordModification(newEntry);
+ return null;
+ }
+ else if (e.hash == hash && eq(key, e.key)) {
+ Object oldValue = e.value;
+ e.value = value;
+ return oldValue;
+ }
+ else
+ e = e.next;
+ }
+ }
+
+
+ /**
+ * Rehashes the contents of this map into a new table
+ * with a larger capacity. This method is called automatically when the
+ * number of keys in this map exceeds its capacity and load factor.
+ */
+ protected void rehash() {
+ Entry[] oldTable = table;
+ int oldCapacity = oldTable.length;
+ if (oldCapacity >= MAXIMUM_CAPACITY) {
+ threshold = Integer.MAX_VALUE; // avoid re-triggering
+ return;
+ }
+
+ int newCapacity = oldCapacity << 1;
+ int mask = newCapacity - 1;
+ threshold = (int)(newCapacity * loadFactor);
+
+ Entry[] newTable = new Entry[newCapacity];
+ /*
+ * Reclassify nodes in each list to new Map. Because we are
+ * using power-of-two expansion, the elements from each bin
+ * must either stay at same index, or move to
+ * oldCapacity+index. We also eliminate unnecessary node
+ * creation by catching cases where old nodes can be reused
+ * because their next fields won't change. Statistically, at
+ * the default threshold, only about one-sixth of them need
+ * cloning. (The nodes they replace will be garbage
+ * collectible as soon as they are no longer referenced by any
+ * reader thread that may be in the midst of traversing table
+ * right now.)
+ */
+
+ for (int i = 0; i < oldCapacity ; i++) {
+ // We need to guarantee that any existing reads of old Map can
+ // proceed. So we cannot yet null out each bin.
+ Entry e = oldTable[i];
+
+ if (e != null) {
+ int idx = e.hash & mask;
+ Entry next = e.next;
+
+ // Single node on list
+ if (next == null)
+ newTable[idx] = e;
+
+ else {
+ // Reuse trailing consecutive sequence of all same bit
+ Entry lastRun = e;
+ int lastIdx = idx;
+ for (Entry last = next; last != null; last = last.next) {
+ int k = last.hash & mask;
+ if (k != lastIdx) {
+ lastIdx = k;
+ lastRun = last;
+ }
+ }
+ newTable[lastIdx] = lastRun;
+
+ // Clone all remaining nodes
+ for (Entry p = e; p != lastRun; p = p.next) {
+ int k = p.hash & mask;
+ newTable[k] = new Entry(p.hash, p.key,
+ p.value, newTable[k]);
+ }
+ }
+ }
+ }
+
+ table = newTable;
+ recordModification(newTable);
+ }
+
+ /**
+ * Removes the key (and its corresponding value) from this
+ * table. This method does nothing if the key is not in the table.
+ *
+ * @param key the key that needs to be removed.
+ * @return the value to which the key had been mapped in this table,
+ * or <code>null</code> if the key did not have a mapping.
+ * @exception NullPointerException if the key is
+ * <code>null</code>.
+ */
+ public Object remove(Object key) {
+ /*
+ Find the entry, then
+ 1. Set value field to null, to force get() to retry
+ 2. Rebuild the list without this entry.
+ All entries following removed node can stay in list, but
+ all preceding ones need to be cloned. Traversals rely
+ on this strategy to ensure that elements will not be
+ repeated during iteration.
+ */
+
+
+ int hash = hash(key);
+ Entry[] tab = table;
+ int index = hash & (tab.length-1);
+ Entry first = tab[index];
+ Entry e = first;
+
+ for (e = first; e != null; e = e.next)
+ if (e.hash == hash && eq(key, e.key))
+ break;
+
+
+ synchronized(this) {
+ if (tab == table) {
+ if (e == null) {
+ if (first == tab[index])
+ return null;
+ }
+ else {
+ Object oldValue = e.value;
+ if (first == tab[index] && oldValue != null) {
+ e.value = null;
+ count--;
+
+ Entry head = e.next;
+ for (Entry p = first; p != e; p = p.next)
+ head = new Entry(p.hash, p.key, p.value, head);
+
+ tab[index] = head;
+ recordModification(head);
+ return oldValue;
+ }
+ }
+ }
+
+ // Wrong list or interference
+ return sremove(key, hash);
+ }
+ }
+
+ /**
+ * Continuation of remove(), called only when sync lock is
+ * held and interference has been detected.
+ **/
+ protected Object sremove(Object key, int hash) {
+ Entry[] tab = table;
+ int index = hash & (tab.length-1);
+ Entry first = tab[index];
+
+ for (Entry e = first; e != null; e = e.next) {
+ if (e.hash == hash && eq(key, e.key)) {
+ Object oldValue = e.value;
+ e.value = null;
+ count--;
+ Entry head = e.next;
+ for (Entry p = first; p != e; p = p.next)
+ head = new Entry(p.hash, p.key, p.value, head);
+
+ tab[index] = head;
+ recordModification(head);
+ return oldValue;
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * Returns <tt>true</tt> if this map maps one or more keys to the
+ * specified value. Note: This method requires a full internal
+ * traversal of the hash table, and so is much slower than
+ * method <tt>containsKey</tt>.
+ *
+ * @param value value whose presence in this map is to be tested.
+ * @return <tt>true</tt> if this map maps one or more keys to the
+ * specified value.
+ * @exception NullPointerException if the value is <code>null</code>.
+ */
+ public boolean containsValue(Object value) {
+ if (value == null) throw new NullPointerException();
+
+ Entry tab[] = getTableForReading();
+
+ for (int i = 0 ; i < tab.length; ++i) {
+ for (Entry e = tab[i] ; e != null ; e = e.next)
+ if (value.equals(e.value))
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Tests if some key maps into the specified value in this table.
+ * This operation is more expensive than the <code>containsKey</code>
+ * method.<p>
+ *
+ * Note that this method is identical in functionality to containsValue,
+ * (which is part of the Map interface in the collections framework).
+ *
+ * @param value a value to search for.
+ * @return <code>true</code> if and only if some key maps to the
+ * <code>value</code> argument in this table as
+ * determined by the <tt>equals</tt> method;
+ * <code>false</code> otherwise.
+ * @exception NullPointerException if the value is <code>null</code>.
+ * @see #containsKey(Object)
+ * @see #containsValue(Object)
+ * @see Map
+ */
+ public boolean contains(Object value) {
+ return containsValue(value);
+ }
+
+
+ /**
+ * Copies all of the mappings from the specified map to this one.
+ *
+ * These mappings replace any mappings that this map had for any of the
+ * keys currently in the specified Map.
+ *
+ * @param t Mappings to be stored in this map.
+ */
+ public synchronized void putAll(Map t) {
+ int n = t.size();
+ if (n == 0)
+ return;
+
+ // Expand enough to hold at least n elements without resizing.
+ // We can only resize table by factor of two at a time.
+ // It is faster to rehash with fewer elements, so do it now.
+ while (n >= threshold)
+ rehash();
+
+ for (Iterator it = t.entrySet().iterator(); it.hasNext();) {
+ Map.Entry entry = (Map.Entry) it.next();
+ Object key = entry.getKey();
+ Object value = entry.getValue();
+ put(key, value);
+ }
+ }
+
+
+ /**
+ * Removes all mappings from this map.
+ */
+ public synchronized void clear() {
+ Entry tab[] = table;
+ for (int i = 0; i < tab.length ; ++i) {
+
+ // must invalidate all to force concurrent get's to wait and then retry
+ for (Entry e = tab[i]; e != null; e = e.next)
+ e.value = null;
+
+ tab[i] = null;
+ }
+ count = 0;
+ recordModification(tab);
+ }
+
+ /**
+ * Returns a shallow copy of this
+ * <tt>ConcurrentReaderHashMap</tt> instance: the keys and
+ * values themselves are not cloned.
+ *
+ * @return a shallow copy of this map.
+ */
+ public synchronized Object clone() {
+ try {
+ ConcurrentReaderHashMap t = (ConcurrentReaderHashMap)super.clone();
+
+ t.keySet = null;
+ t.entrySet = null;
+ t.values = null;
+
+ Entry[] tab = table;
+ t.table = new Entry[tab.length];
+ Entry[] ttab = t.table;
+
+ for (int i = 0; i < tab.length; ++i) {
+ Entry first = null;
+ for (Entry e = tab[i]; e != null; e = e.next)
+ first = new Entry(e.hash, e.key, e.value, first);
+ ttab[i] = first;
+ }
+
+ return t;
+ }
+ catch (CloneNotSupportedException e) {
+ // this shouldn't happen, since we are Cloneable
+ throw new InternalError();
+ }
+ }
+
+ // Views
+
+ protected transient Set keySet = null;
+ protected transient Set entrySet = null;
+ protected transient Collection values = null;
+
+ /**
+ * Returns a set view of the keys contained in this map. The set is
+ * backed by the map, so changes to the map are reflected in the set, and
+ * vice-versa. The set supports element removal, which removes the
+ * corresponding mapping from this map, via the <tt>Iterator.remove</tt>,
+ * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt>, and
+ * <tt>clear</tt> operations. It does not support the <tt>add</tt> or
+ * <tt>addAll</tt> operations.
+ *
+ * @return a set view of the keys contained in this map.
+ */
+ public Set keySet() {
+ Set ks = keySet;
+ return (ks != null)? ks : (keySet = new KeySet());
+ }
+
+ private class KeySet extends AbstractSet {
+ public Iterator iterator() {
+ return new KeyIterator();
+ }
+ public int size() {
+ return ConcurrentReaderHashMap.this.size();
+ }
+ public boolean contains(Object o) {
+ return ConcurrentReaderHashMap.this.containsKey(o);
+ }
+ public boolean remove(Object o) {
+ return ConcurrentReaderHashMap.this.remove(o) != null;
+ }
+ public void clear() {
+ ConcurrentReaderHashMap.this.clear();
+ }
+ public Object[] toArray() {
+ Collection c = new ArrayList();
+ for (Iterator i = iterator(); i.hasNext(); )
+ c.add(i.next());
+ return c.toArray();
+ }
+ public Object[] toArray(Object[] a) {
+ Collection c = new ArrayList();
+ for (Iterator i = iterator(); i.hasNext(); )
+ c.add(i.next());
+ return c.toArray(a);
+ }
+ }
+
+ /**
+ * Returns a collection view of the values contained in this map. The
+ * collection is backed by the map, so changes to the map are reflected in
+ * the collection, and vice-versa. The collection supports element
+ * removal, which removes the corresponding mapping from this map, via the
+ * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,
+ * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> operations.
+ * It does not support the <tt>add</tt> or <tt>addAll</tt> operations.
+ *
+ * @return a collection view of the values contained in this map.
+ */
+ public Collection values() {
+ Collection vs = values;
+ return (vs != null)? vs : (values = new Values());
+ }
+
+ private class Values extends AbstractCollection {
+ public Iterator iterator() {
+ return new ValueIterator();
+ }
+ public int size() {
+ return ConcurrentReaderHashMap.this.size();
+ }
+ public boolean contains(Object o) {
+ return ConcurrentReaderHashMap.this.containsValue(o);
+ }
+ public void clear() {
+ ConcurrentReaderHashMap.this.clear();
+ }
+ public Object[] toArray() {
+ Collection c = new ArrayList();
+ for (Iterator i = iterator(); i.hasNext(); )
+ c.add(i.next());
+ return c.toArray();
+ }
+ public Object[] toArray(Object[] a) {
+ Collection c = new ArrayList();
+ for (Iterator i = iterator(); i.hasNext(); )
+ c.add(i.next());
+ return c.toArray(a);
+ }
+ }
+
+ /**
+ * Returns a collection view of the mappings contained in this map. Each
+ * element in the returned collection is a <tt>Map.Entry</tt>. The
+ * collection is backed by the map, so changes to the map are reflected in
+ * the collection, and vice-versa. The collection supports element
+ * removal, which removes the corresponding mapping from the map, via the
+ * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,
+ * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> operations.
+ * It does not support the <tt>add</tt> or <tt>addAll</tt> operations.
+ *
+ * @return a collection view of the mappings contained in this map.
+ */
+ public Set entrySet() {
+ Set es = entrySet;
+ return (es != null) ? es : (entrySet = new EntrySet());
+ }
+
+ private class EntrySet extends AbstractSet {
+ public Iterator iterator() {
+ return new HashIterator();
+ }
+ public boolean contains(Object o) {
+ if (!(o instanceof Map.Entry))
+ return false;
+ Map.Entry entry = (Map.Entry)o;
+ Object v = ConcurrentReaderHashMap.this.get(entry.getKey());
+ return v != null && v.equals(entry.getValue());
+ }
+ public boolean remove(Object o) {
+ if (!(o instanceof Map.Entry))
+ return false;
+ return ConcurrentReaderHashMap.this.findAndRemoveEntry((Map.Entry)o);
+ }
+ public int size() {
+ return ConcurrentReaderHashMap.this.size();
+ }
+ public void clear() {
+ ConcurrentReaderHashMap.this.clear();
+ }
+ public Object[] toArray() {
+ Collection c = new ArrayList();
+ for (Iterator i = iterator(); i.hasNext(); )
+ c.add(i.next());
+ return c.toArray();
+ }
+ public Object[] toArray(Object[] a) {
+ Collection c = new ArrayList();
+ for (Iterator i = iterator(); i.hasNext(); )
+ c.add(i.next());
+ return c.toArray(a);
+ }
+ }
+
+ /**
+ * Helper method for entrySet.remove
+ **/
+ protected synchronized boolean findAndRemoveEntry(Map.Entry entry) {
+ Object key = entry.getKey();
+ Object v = get(key);
+ if (v != null && v.equals(entry.getValue())) {
+ remove(key);
+ return true;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * Returns an enumeration of the keys in this table.
+ *
+ * @return an enumeration of the keys in this table.
+ * @see Enumeration
+ * @see #elements()
+ * @see #keySet()
+ * @see Map
+ */
+ public Enumeration keys() {
+ return new KeyIterator();
+ }
+
+ /**
+ * Returns an enumeration of the values in this table.
+ * Use the Enumeration methods on the returned object to fetch the elements
+ * sequentially.
+ *
+ * @return an enumeration of the values in this table.
+ * @see java.util.Enumeration
+ * @see #keys()
+ * @see #values()
+ * @see Map
+ */
+ public Enumeration elements() {
+ return new ValueIterator();
+ }
+
+
+ /**
+ * ConcurrentReaderHashMap collision list entry.
+ */
+ protected static class Entry implements Map.Entry {
+
+ /*
+ The use of volatile for value field ensures that
+ we can detect status changes without synchronization.
+ The other fields are never changed, and are
+ marked as final.
+ */
+ protected final int hash;
+ protected final Object key;
+ protected final Entry next;
+ protected volatile Object value;
+
+ Entry(int hash, Object key, Object value, Entry next) {
+ this.hash = hash;
+ this.key = key;
+ this.next = next;
+ this.value = value;
+ }
+
+ // Map.Entry Ops
+
+ public Object getKey() {
+ return key;
+ }
+
+ /**
+ * Get the value. Note: In an entrySet or entrySet.iterator,
+ * unless the set or iterator is used under synchronization of the
+ * table as a whole (or you can otherwise guarantee lack of
+ * concurrent modification), <tt>getValue</tt> <em>might</em>
+ * return null, reflecting the fact that the entry has been
+ * concurrently removed. However, there are no assurances that
+ * concurrent removals will be reflected using this method.
+ *
+ * @return the current value, or null if the entry has been
+ * detectably removed.
+ **/
+ public Object getValue() {
+ return value;
+ }
+
+ /**
+ * Set the value of this entry. Note: In an entrySet or
+ * entrySet.iterator), unless the set or iterator is used under
+ * synchronization of the table as a whole (or you can otherwise
+ * guarantee lack of concurrent modification), <tt>setValue</tt>
+ * is not strictly guaranteed to actually replace the value field
+ * obtained via the <tt>get</tt> operation of the underlying hash
+ * table in multi-threaded applications. If iterator-wide
+ * synchronization is not used, and any other concurrent
+ * <tt>put</tt> or <tt>remove</tt> operations occur, sometimes
+ * even to <em>other</em> entries, then this change is not
+ * guaranteed to be reflected in the hash table. (It might, or it
+ * might not. There are no assurances either way.)
+ *
+ * @param value the new value.
+ * @return the previous value, or null if entry has been detectably
+ * removed.
+ * @exception NullPointerException if the value is <code>null</code>.
+ *
+ **/
+ public Object setValue(Object value) {
+ if (value == null)
+ throw new NullPointerException();
+ Object oldValue = this.value;
+ this.value = value;
+ return oldValue;
+ }
+
+ public boolean equals(Object o) {
+ if (!(o instanceof Map.Entry))
+ return false;
+ Map.Entry e = (Map.Entry)o;
+ return (key.equals(e.getKey()) && value.equals(e.getValue()));
+ }
+
+ public int hashCode() {
+ return key.hashCode() ^ value.hashCode();
+ }
+
+ public String toString() {
+ return key + "=" + value;
+ }
+
+ }
+
+ protected class HashIterator implements Iterator, Enumeration {
+ protected final Entry[] tab; // snapshot of table
+ protected int index; // current slot
+ protected Entry entry = null; // current node of slot
+ protected Object currentKey; // key for current node
+ protected Object currentValue; // value for current node
+ protected Entry lastReturned = null; // last node returned by next
+
+ protected HashIterator() {
+ tab = ConcurrentReaderHashMap.this.getTableForReading();
+ index = tab.length - 1;
+ }
+
+ public boolean hasMoreElements() { return hasNext(); }
+ public Object nextElement() { return next(); }
+
+
+ public boolean hasNext() {
+
+ /*
+ currentKey and currentValue are set here to ensure that next()
+ returns normally if hasNext() returns true. This avoids
+ surprises especially when final element is removed during
+ traversal -- instead, we just ignore the removal during
+ current traversal.
+ */
+
+ for (;;) {
+ if (entry != null) {
+ Object v = entry.value;
+ if (v != null) {
+ currentKey = entry.key;
+ currentValue = v;
+ return true;
+ }
+ else
+ entry = entry.next;
+ }
+
+ while (entry == null && index >= 0)
+ entry = tab[index--];
+
+ if (entry == null) {
+ currentKey = currentValue = null;
+ return false;
+ }
+ }
+ }
+
+ protected Object returnValueOfNext() { return entry; }
+
+ public Object next() {
+ if (currentKey == null && !hasNext())
+ throw new NoSuchElementException();
+
+ Object result = returnValueOfNext();
+ lastReturned = entry;
+ currentKey = currentValue = null;
+ entry = entry.next;
+ return result;
+ }
+
+ public void remove() {
+ if (lastReturned == null)
+ throw new IllegalStateException();
+ ConcurrentReaderHashMap.this.remove(lastReturned.key);
+ lastReturned = null;
+ }
+
+ }
+
+
+ protected class KeyIterator extends HashIterator {
+ protected Object returnValueOfNext() { return currentKey; }
+ }
+
+ protected class ValueIterator extends HashIterator {
+ protected Object returnValueOfNext() { return currentValue; }
+ }
+
+
+
+ /**
+ * Save the state of the <tt>ConcurrentReaderHashMap</tt>
+ * instance to a stream (i.e.,
+ * serialize it).
+ *
+ * @param s the stream
+ * @serialData The <i>capacity</i> of the
+ * ConcurrentReaderHashMap (the length of the
+ * bucket array) is emitted (int), followed by the
+ * <i>size</i> of the ConcurrentReaderHashMap (the number of key-value
+ * mappings), followed by the key (Object) and value (Object)
+ * for each key-value mapping represented by the ConcurrentReaderHashMap
+ * The key-value mappings are emitted in no particular order.
+ */
+ private synchronized void writeObject(java.io.ObjectOutputStream s)
+ throws IOException {
+ // Write out the threshold, loadfactor, and any hidden stuff
+ s.defaultWriteObject();
+
+ // Write out number of buckets
+ s.writeInt(table.length);
+
+ // Write out size (number of Mappings)
+ s.writeInt(count);
+
+ // Write out keys and values (alternating)
+ for (int index = table.length-1; index >= 0; index--) {
+ Entry entry = table[index];
+
+ while (entry != null) {
+ s.writeObject(entry.key);
+ s.writeObject(entry.value);
+ entry = entry.next;
+ }
+ }
+ }
+
+ /**
+ * Reconstitute the <tt>ConcurrentReaderHashMap</tt>
+ * instance from a stream (i.e.,
+ * deserialize it).
+ *
+ * @param s the stream
+ */
+ private synchronized void readObject(java.io.ObjectInputStream s)
+ throws IOException, ClassNotFoundException {
+ // Read in the threshold, loadfactor, and any hidden stuff
+ s.defaultReadObject();
+
+ // Read in number of buckets and allocate the bucket array;
+ int numBuckets = s.readInt();
+ table = new Entry[numBuckets];
+
+ // Read in size (number of Mappings)
+ int size = s.readInt();
+
+ // Read the keys and values, and put the mappings in the table
+ for (int i=0; i<size; i++) {
+ Object key = s.readObject();
+ Object value = s.readObject();
+ put(key, value);
+ }
+ }
+
+ /**
+ * @return the number of slots in this table
+ **/
+ public synchronized int capacity() {
+ return table.length;
+ }
+
+ /**
+ * @return the load factor
+ **/
+ public float loadFactor() {
+ return loadFactor;
+ }
+}
diff --git a/src/main/java/org/codehaus/groovy/runtime/metaclass/MethodSelectionException.java b/src/main/java/org/codehaus/groovy/runtime/metaclass/MethodSelectionException.java
index 06272ed..027e7ff 100644
--- a/src/main/java/org/codehaus/groovy/runtime/metaclass/MethodSelectionException.java
+++ b/src/main/java/org/codehaus/groovy/runtime/metaclass/MethodSelectionException.java
@@ -1,102 +1,102 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.codehaus.groovy.runtime.metaclass;
-
-import groovy.lang.GroovyRuntimeException;
-import groovy.lang.MetaMethod;
-import org.codehaus.groovy.reflection.CachedConstructor;
-import org.codehaus.groovy.util.FastArray;
-
-import java.lang.reflect.Modifier;
-
-/**
- * This exception is thrown if the runtime is unable to select
- * a method. This class builds the exception text when calling
- * getMessage.
- * <p>
- * <b>Note:</b> This exception as for internal use only!
- *
- * @since Groovy 1.1
- */
-public class MethodSelectionException extends GroovyRuntimeException {
-
- private static final long serialVersionUID = 8126246630023758333L;
- private final String methodName;
- private final FastArray methods;
- private final Class[] arguments;
-
- /**
- * Creates a new MethodSelectionException.
- * @param methodName name of the method
- * @param methods a FastArray of methods
- * @param arguments the method call argument classes
- */
- public MethodSelectionException(String methodName, FastArray methods, Class[] arguments) {
- super(methodName);
- this.methodName = methodName;
- this.arguments = arguments;
- this.methods = methods;
- }
-
- public String getMessage() {
- StringBuilder buffer = new StringBuilder();
- buffer.append("Could not find which method ").append(methodName);
- appendClassNames(buffer,arguments);
- buffer.append(" to invoke from this list:");
- appendMethods(buffer);
- return buffer.toString();
- }
-
-
- private static void appendClassNames(StringBuilder argBuf, Class[] classes) {
- argBuf.append("(");
- for (int i = 0; i < classes.length; i++) {
- if (i > 0) {
- argBuf.append(", ");
- }
- Class clazz = classes[i];
- String name = clazz==null? "null": clazz.getName();
- argBuf.append(name);
- }
- argBuf.append(")");
- }
-
- private void appendMethods(StringBuilder buffer) {
- for (int i = 0; i < methods.size; i++) {
- buffer.append("\n ");
- Object methodOrConstructor = methods.get(i);
- if (methodOrConstructor instanceof MetaMethod) {
- MetaMethod method = (MetaMethod) methodOrConstructor;
- buffer.append(Modifier.toString(method.getModifiers()));
- buffer.append(" ").append(method.getReturnType().getName());
- buffer.append(" ").append(method.getDeclaringClass().getName());
- buffer.append("#");
- buffer.append(method.getName());
- appendClassNames(buffer,method.getNativeParameterTypes());
- }
- else {
- CachedConstructor method = (CachedConstructor) methodOrConstructor;
- buffer.append(Modifier.toString(method.cachedConstructor.getModifiers()));
- buffer.append(" ").append(method.cachedConstructor.getDeclaringClass().getName());
- buffer.append("#<init>");
- appendClassNames(buffer,method.getNativeParameterTypes());
- }
- }
- }
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.codehaus.groovy.runtime.metaclass;
+
+import groovy.lang.GroovyRuntimeException;
+import groovy.lang.MetaMethod;
+import org.codehaus.groovy.reflection.CachedConstructor;
+import org.codehaus.groovy.util.FastArray;
+
+import java.lang.reflect.Modifier;
+
+/**
+ * This exception is thrown if the runtime is unable to select
+ * a method. This class builds the exception text when calling
+ * getMessage.
+ * <p>
+ * <b>Note:</b> This exception as for internal use only!
+ *
+ * @since Groovy 1.1
+ */
+public class MethodSelectionException extends GroovyRuntimeException {
+
+ private static final long serialVersionUID = 8126246630023758333L;
+ private final String methodName;
+ private final FastArray methods;
+ private final Class[] arguments;
+
+ /**
+ * Creates a new MethodSelectionException.
+ * @param methodName name of the method
+ * @param methods a FastArray of methods
+ * @param arguments the method call argument classes
+ */
+ public MethodSelectionException(String methodName, FastArray methods, Class[] arguments) {
+ super(methodName);
+ this.methodName = methodName;
+ this.arguments = arguments;
+ this.methods = methods;
+ }
+
+ public String getMessage() {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append("Could not find which method ").append(methodName);
+ appendClassNames(buffer,arguments);
+ buffer.append(" to invoke from this list:");
+ appendMethods(buffer);
+ return buffer.toString();
+ }
+
+
+ private static void appendClassNames(StringBuilder argBuf, Class[] classes) {
+ argBuf.append("(");
+ for (int i = 0; i < classes.length; i++) {
+ if (i > 0) {
+ argBuf.append(", ");
+ }
+ Class clazz = classes[i];
+ String name = clazz==null? "null": clazz.getName();
+ argBuf.append(name);
+ }
+ argBuf.append(")");
+ }
+
+ private void appendMethods(StringBuilder buffer) {
+ for (int i = 0; i < methods.size; i++) {
+ buffer.append("\n ");
+ Object methodOrConstructor = methods.get(i);
+ if (methodOrConstructor instanceof MetaMethod) {
+ MetaMethod method = (MetaMethod) methodOrConstructor;
+ buffer.append(Modifier.toString(method.getModifiers()));
+ buffer.append(" ").append(method.getReturnType().getName());
+ buffer.append(" ").append(method.getDeclaringClass().getName());
+ buffer.append("#");
+ buffer.append(method.getName());
+ appendClassNames(buffer,method.getNativeParameterTypes());
+ }
+ else {
+ CachedConstructor method = (CachedConstructor) methodOrConstructor;
+ buffer.append(Modifier.toString(method.cachedConstructor.getModifiers()));
+ buffer.append(" ").append(method.cachedConstructor.getDeclaringClass().getName());
+ buffer.append("#<init>");
+ appendClassNames(buffer,method.getNativeParameterTypes());
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/src/main/java/org/codehaus/groovy/runtime/typehandling/GroovyCastException.java b/src/main/java/org/codehaus/groovy/runtime/typehandling/GroovyCastException.java
index f9cace8..053353a 100644
--- a/src/main/java/org/codehaus/groovy/runtime/typehandling/GroovyCastException.java
+++ b/src/main/java/org/codehaus/groovy/runtime/typehandling/GroovyCastException.java
@@ -1,87 +1,87 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.codehaus.groovy.runtime.typehandling;
-
-public class GroovyCastException extends ClassCastException {
-
- private static final long serialVersionUID = 6859089155641797356L;
-
- /**
- * @param objectToCast object we tried to cast
- * @param classToCastTo class we tried to cast to
- * @param cause not kept but we pass on message from this Exception if any
- */
- public GroovyCastException(Object objectToCast, Class classToCastTo, Exception cause) {
- super(makeMessage(objectToCast,classToCastTo) + " due to: " +
- cause.getClass().getName() + (cause.getMessage() == null ? "" : ": " + cause.getMessage()));
- }
-
- /**
- * @param objectToCast object we tried to cast
- * @param classToCastTo class we tried to cast to
- */
- public GroovyCastException(Object objectToCast, Class classToCastTo) {
- super(makeMessage(objectToCast,classToCastTo));
- }
-
- /**
- * @param message custom Exception message
- */
- public GroovyCastException(String message) {
- super(message);
- }
-
- private static String makeMessage(Object objectToCast, Class classToCastTo) {
- String classToCastFrom;
- Object msgObject = objectToCast;
- if (objectToCast!=null) {
- classToCastFrom = objectToCast.getClass().getName();
- } else {
- msgObject = "null";
- classToCastFrom = "null";
- }
- String msg =
- "Cannot cast object '" + msgObject + "' " +
- "with class '" + classToCastFrom + "' " +
- "to class '" + classToCastTo.getName() + "'";
-
- if (objectToCast==null){
- msg += getWrapper(classToCastTo);
- }
-
- return msg;
- }
-
- private static String getWrapper(Class cls) {
- Class ncls = cls;
- if (cls==byte.class) {ncls=Byte.class;}
- else if (cls==short.class) {ncls=Short.class;}
- else if (cls==char.class) {ncls=Character.class;}
- else if (cls==int.class) {ncls=Integer.class;}
- else if (cls==long.class) {ncls=Long.class;}
- else if (cls==float.class) {ncls=Float.class;}
- else if (cls==double.class) {ncls=Double.class;}
- if (cls!=null && ncls!=cls) {
- String msg = ". Try '" + ncls.getName() + "' instead";
- return msg;
- }
- return "";
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.codehaus.groovy.runtime.typehandling;
+
+public class GroovyCastException extends ClassCastException {
+
+ private static final long serialVersionUID = 6859089155641797356L;
+
+ /**
+ * @param objectToCast object we tried to cast
+ * @param classToCastTo class we tried to cast to
+ * @param cause not kept but we pass on message from this Exception if any
+ */
+ public GroovyCastException(Object objectToCast, Class classToCastTo, Exception cause) {
+ super(makeMessage(objectToCast,classToCastTo) + " due to: " +
+ cause.getClass().getName() + (cause.getMessage() == null ? "" : ": " + cause.getMessage()));
+ }
+
+ /**
+ * @param objectToCast object we tried to cast
+ * @param classToCastTo class we tried to cast to
+ */
+ public GroovyCastException(Object objectToCast, Class classToCastTo) {
+ super(makeMessage(objectToCast,classToCastTo));
+ }
+
+ /**
+ * @param message custom Exception message
+ */
+ public GroovyCastException(String message) {
+ super(message);
+ }
+
+ private static String makeMessage(Object objectToCast, Class classToCastTo) {
+ String classToCastFrom;
+ Object msgObject = objectToCast;
+ if (objectToCast!=null) {
+ classToCastFrom = objectToCast.getClass().getName();
+ } else {
+ msgObject = "null";
+ classToCastFrom = "null";
+ }
+ String msg =
+ "Cannot cast object '" + msgObject + "' " +
+ "with class '" + classToCastFrom + "' " +
+ "to class '" + classToCastTo.getName() + "'";
+
+ if (objectToCast==null){
+ msg += getWrapper(classToCastTo);
+ }
+
+ return msg;
+ }
+
+ private static String getWrapper(Class cls) {
+ Class ncls = cls;
+ if (cls==byte.class) {ncls=Byte.class;}
+ else if (cls==short.class) {ncls=Short.class;}
+ else if (cls==char.class) {ncls=Character.class;}
+ else if (cls==int.class) {ncls=Integer.class;}
+ else if (cls==long.class) {ncls=Long.class;}
+ else if (cls==float.class) {ncls=Float.class;}
+ else if (cls==double.class) {ncls=Double.class;}
+ if (cls!=null && ncls!=cls) {
+ String msg = ". Try '" + ncls.getName() + "' instead";
+ return msg;
+ }
+ return "";
+ }
+
+}
diff --git a/src/main/java/org/codehaus/groovy/runtime/typehandling/package.html b/src/main/java/org/codehaus/groovy/runtime/typehandling/package.html
index fab5318..a5f4506 100644
--- a/src/main/java/org/codehaus/groovy/runtime/typehandling/package.html
+++ b/src/main/java/org/codehaus/groovy/runtime/typehandling/package.html
@@ -1,30 +1,30 @@
-<!--
-
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied. See the License for the
- specific language governing permissions and limitations
- under the License.
-
--->
-<html>
- <head>
- <title>package org.codehaus.groovy.runtime.typehandling*</title>
- </head>
- <body>
- <p>Classes used to execute special actions based on the type.
- This includes mathematical operations and wrapper classes.
- </p>
- </body>
-</html>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+<html>
+ <head>
+ <title>package org.codehaus.groovy.runtime.typehandling*</title>
+ </head>
+ <body>
+ <p>Classes used to execute special actions based on the type.
+ This includes mathematical operations and wrapper classes.
+ </p>
+ </body>
+</html>
diff --git a/src/main/java/org/codehaus/groovy/tools/StringHelper.java b/src/main/java/org/codehaus/groovy/tools/StringHelper.java
index 53b3b9e..c01388a 100644
--- a/src/main/java/org/codehaus/groovy/tools/StringHelper.java
+++ b/src/main/java/org/codehaus/groovy/tools/StringHelper.java
@@ -1,86 +1,86 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.codehaus.groovy.tools;
-
-import java.util.LinkedList;
-import java.util.List;
-
-public class StringHelper {
- private static final char
- SPACE = ' ', SINGLE_QUOTE = '\'', DOUBLE_QUOTE = '"';
- private static final String[] EMPTY_STRING_ARRAY = new String[0];
-
- /**
- * This method tokenizes a string by space characters,
- * but ignores spaces in quoted parts,that are parts in
- * '' or "". The method does allows the usage of "" in ''
- * and '' in "". The space character between tokens is not
- * returned.
- *
- * @param s the string to tokenize
- * @return the tokens
- */
- public static String[] tokenizeUnquoted(String s) {
- List tokens = new LinkedList();
- int first = 0;
- while (first < s.length()) {
- first = skipWhitespace(s, first);
- int last = scanToken(s, first);
- if (first < last) {
- tokens.add(s.substring(first, last));
- }
- first = last;
- }
- return (String[])tokens.toArray(EMPTY_STRING_ARRAY);
- }
-
- private static int scanToken(String s, int pos0) {
- int pos = pos0;
- while (pos < s.length()) {
- char c = s.charAt(pos);
- if (SPACE==c) break;
- pos++;
- if (SINGLE_QUOTE == c) {
- pos = scanQuoted(s, pos, SINGLE_QUOTE);
- } else if (DOUBLE_QUOTE == c) {
- pos = scanQuoted(s, pos, DOUBLE_QUOTE);
- }
- }
- return pos;
- }
-
- private static int scanQuoted(String s, int pos0, char quote) {
- int pos = pos0;
- while (pos < s.length()) {
- char c = s.charAt(pos++);
- if (quote == c) break;
- }
- return pos;
- }
-
- private static int skipWhitespace(String s, int pos0) {
- int pos = pos0;
- while (pos < s.length()) {
- char c = s.charAt(pos);
- if (SPACE!=c) break;
- pos++;
- }
- return pos;
- }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.codehaus.groovy.tools;
+
+import java.util.LinkedList;
+import java.util.List;
+
+public class StringHelper {
+ private static final char
+ SPACE = ' ', SINGLE_QUOTE = '\'', DOUBLE_QUOTE = '"';
+ private static final String[] EMPTY_STRING_ARRAY = new String[0];
+
+ /**
+ * This method tokenizes a string by space characters,
+ * but ignores spaces in quoted parts,that are parts in
+ * '' or "". The method does allows the usage of "" in ''
+ * and '' in "". The space character between tokens is not
+ * returned.
+ *
+ * @param s the string to tokenize
+ * @return the tokens
+ */
+ public static String[] tokenizeUnquoted(String s) {
+ List tokens = new LinkedList();
+ int first = 0;
+ while (first < s.length()) {
+ first = skipWhitespace(s, first);
+ int last = scanToken(s, first);
+ if (first < last) {
+ tokens.add(s.substring(first, last));
+ }
+ first = last;
+ }
+ return (String[])tokens.toArray(EMPTY_STRING_ARRAY);
+ }
+
+ private static int scanToken(String s, int pos0) {
+ int pos = pos0;
+ while (pos < s.length()) {
+ char c = s.charAt(pos);
+ if (SPACE==c) break;
+ pos++;
+ if (SINGLE_QUOTE == c) {
+ pos = scanQuoted(s, pos, SINGLE_QUOTE);
+ } else if (DOUBLE_QUOTE == c) {
+ pos = scanQuoted(s, pos, DOUBLE_QUOTE);
+ }
+ }
+ return pos;
+ }
+
+ private static int scanQuoted(String s, int pos0, char quote) {
+ int pos = pos0;
+ while (pos < s.length()) {
+ char c = s.charAt(pos++);
+ if (quote == c) break;
+ }
+ return pos;
+ }
+
+ private static int skipWhitespace(String s, int pos0) {
+ int pos = pos0;
+ while (pos < s.length()) {
+ char c = s.charAt(pos);
+ if (SPACE!=c) break;
+ pos++;
+ }
+ return pos;
+ }
+}
diff --git a/src/main/java/org/codehaus/groovy/transform/AbstractASTTransformUtil.java b/src/main/java/org/codehaus/groovy/transform/AbstractASTTransformUtil.java
index de50cb5..35bf848 100644
--- a/src/main/java/org/codehaus/groovy/transform/AbstractASTTransformUtil.java
+++ b/src/main/java/org/codehaus/groovy/transform/AbstractASTTransformUtil.java
@@ -1,184 +1,184 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.codehaus.groovy.transform;
-
-import org.codehaus.groovy.ast.ClassNode;
-import org.codehaus.groovy.ast.FieldNode;
-import org.codehaus.groovy.ast.PropertyNode;
-import org.codehaus.groovy.ast.expr.BooleanExpression;
-import org.codehaus.groovy.ast.expr.Expression;
-import org.codehaus.groovy.ast.stmt.ExpressionStatement;
-import org.codehaus.groovy.ast.stmt.IfStatement;
-import org.codehaus.groovy.ast.stmt.Statement;
-import org.codehaus.groovy.ast.tools.GeneralUtils;
-import org.objectweb.asm.Opcodes;
-
-import java.util.List;
-
-/**
- * @deprecated use org.codehaus.groovy.ast.tools.GeneralUtils
- */
-@Deprecated
-public abstract class AbstractASTTransformUtil implements Opcodes {
- @Deprecated
- public static Statement assignStatement(Expression target, Expression value) {
- return GeneralUtils.assignS(target, value);
- }
-
- @Deprecated
- public static Statement createConstructorStatementDefault(FieldNode fNode) {
- return GeneralUtils.createConstructorStatementDefault(fNode);
- }
-
- @Deprecated
- public static ExpressionStatement declStatement(Expression result, Expression init) {
- return (ExpressionStatement) GeneralUtils.declS(result, init);
- }
-
- @Deprecated
- public static BooleanExpression differentExpr(Expression self, Expression other) {
- return GeneralUtils.notX(GeneralUtils.sameX(self, other));
- }
-
- @Deprecated
- public static BooleanExpression differentFieldExpr(FieldNode fNode, Expression other) {
- return GeneralUtils.notX(GeneralUtils.hasSameFieldX(fNode, other));
- }
-
- @Deprecated
- public static BooleanExpression differentPropertyExpr(PropertyNode pNode, Expression other) {
- return GeneralUtils.notX(GeneralUtils.hasSamePropertyX(pNode, other));
- }
-
- @Deprecated
- public static BooleanExpression equalsNullExpr(Expression argExpr) {
- return GeneralUtils.equalsNullX(argExpr);
- }
-
- @Deprecated
- public static Expression findArg(String argName) {
- return GeneralUtils.findArg(argName);
- }
-
- @Deprecated
- public static List<FieldNode> getInstanceNonPropertyFields(ClassNode cNode) {
- return GeneralUtils.getInstanceNonPropertyFields(cNode);
- }
-
- @Deprecated
- public static List<PropertyNode> getInstanceProperties(ClassNode cNode) {
- return GeneralUtils.getInstanceProperties(cNode);
- }
-
- @Deprecated
- public static List<FieldNode> getInstancePropertyFields(ClassNode cNode) {
- return GeneralUtils.getInstancePropertyFields(cNode);
- }
-
- @Deprecated
- public static List<FieldNode> getSuperNonPropertyFields(ClassNode cNode) {
- return GeneralUtils.getSuperNonPropertyFields(cNode);
- }
-
- @Deprecated
- public static List<FieldNode> getSuperPropertyFields(ClassNode cNode) {
- return GeneralUtils.getSuperPropertyFields(cNode);
- }
-
- @Deprecated
- public static boolean hasDeclaredMethod(ClassNode cNode, String name, int argsCount) {
- return GeneralUtils.hasDeclaredMethod(cNode, name, argsCount);
- }
-
- @Deprecated
- public static BooleanExpression identicalExpr(Expression self, Expression other) {
- return GeneralUtils.sameX(self, other);
- }
-
- @Deprecated
- public static BooleanExpression isInstanceOf(Expression objectExpression, ClassNode cNode) {
- return GeneralUtils.isInstanceOfX(objectExpression, cNode);
- }
-
- @Deprecated
- public static BooleanExpression isInstanceof(ClassNode cNode, Expression other) {
- return GeneralUtils.isInstanceOfX(other, cNode);
- }
-
- @Deprecated
- public static BooleanExpression isOneExpr(Expression expr) {
- return GeneralUtils.isOneX(expr);
- }
-
- @Deprecated
- public static boolean isOrImplements(ClassNode fieldType, ClassNode interfaceType) {
- return GeneralUtils.isOrImplements(fieldType, interfaceType);
- }
-
- @Deprecated
- public static BooleanExpression isTrueExpr(Expression argExpr) {
- return GeneralUtils.isTrueX(argExpr);
- }
-
- @Deprecated
- public static BooleanExpression isZeroExpr(Expression expr) {
- return GeneralUtils.isZeroX(expr);
- }
-
- @Deprecated
- public static BooleanExpression notNullExpr(Expression argExpr) {
- return GeneralUtils.notNullX(argExpr);
- }
-
- @Deprecated
- public static Statement returnFalseIfFieldNotEqual(FieldNode fNode, Expression other) {
- return GeneralUtils.ifS(GeneralUtils.notX(GeneralUtils.hasEqualFieldX(fNode, other)), GeneralUtils.returnS(GeneralUtils.constX(Boolean.FALSE)));
- }
-
- @Deprecated
- public static Statement returnFalseIfNotInstanceof(ClassNode cNode, Expression other) {
- return GeneralUtils.ifS(GeneralUtils.notX(GeneralUtils.isInstanceOfX(other, cNode)), GeneralUtils.returnS(GeneralUtils.constX(Boolean.FALSE)));
- }
-
- @Deprecated
- public static IfStatement returnFalseIfNull(Expression other) {
- return (IfStatement) GeneralUtils.ifS(GeneralUtils.equalsNullX(other), GeneralUtils.returnS(GeneralUtils.constX(Boolean.FALSE)));
- }
-
- @Deprecated
- public static Statement returnFalseIfPropertyNotEqual(PropertyNode pNode, Expression other) {
- return GeneralUtils.ifS(GeneralUtils.notX(GeneralUtils.hasEqualPropertyX(pNode, other)), GeneralUtils.returnS(GeneralUtils.constX(Boolean.FALSE)));
- }
-
- @Deprecated
- public static Statement returnFalseIfWrongType(ClassNode cNode, Expression other) {
- return GeneralUtils.ifS(GeneralUtils.notX(GeneralUtils.hasClassX(other, cNode)), GeneralUtils.returnS(GeneralUtils.constX(Boolean.FALSE)));
- }
-
- @Deprecated
- public static IfStatement returnTrueIfIdentical(Expression self, Expression other) {
- return (IfStatement) GeneralUtils.ifS(GeneralUtils.sameX(self, other), GeneralUtils.returnS(GeneralUtils.constX(Boolean.TRUE)));
- }
-
- @Deprecated
- public static Statement safeExpression(Expression fieldExpr, Expression expression) {
- return GeneralUtils.safeExpression(fieldExpr, expression);
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.codehaus.groovy.transform;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.PropertyNode;
+import org.codehaus.groovy.ast.expr.BooleanExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.stmt.ExpressionStatement;
+import org.codehaus.groovy.ast.stmt.IfStatement;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.ast.tools.GeneralUtils;
+import org.objectweb.asm.Opcodes;
+
+import java.util.List;
+
+/**
+ * @deprecated use org.codehaus.groovy.ast.tools.GeneralUtils
+ */
+@Deprecated
+public abstract class AbstractASTTransformUtil implements Opcodes {
+ @Deprecated
+ public static Statement assignStatement(Expression target, Expression value) {
+ return GeneralUtils.assignS(target, value);
+ }
+
+ @Deprecated
+ public static Statement createConstructorStatementDefault(FieldNode fNode) {
+ return GeneralUtils.createConstructorStatementDefault(fNode);
+ }
+
+ @Deprecated
+ public static ExpressionStatement declStatement(Expression result, Expression init) {
+ return (ExpressionStatement) GeneralUtils.declS(result, init);
+ }
+
+ @Deprecated
+ public static BooleanExpression differentExpr(Expression self, Expression other) {
+ return GeneralUtils.notX(GeneralUtils.sameX(self, other));
+ }
+
+ @Deprecated
+ public static BooleanExpression differentFieldExpr(FieldNode fNode, Expression other) {
+ return GeneralUtils.notX(GeneralUtils.hasSameFieldX(fNode, other));
+ }
+
+ @Deprecated
+ public static BooleanExpression differentPropertyExpr(PropertyNode pNode, Expression other) {
+ return GeneralUtils.notX(GeneralUtils.hasSamePropertyX(pNode, other));
+ }
+
+ @Deprecated
+ public static BooleanExpression equalsNullExpr(Expression argExpr) {
+ return GeneralUtils.equalsNullX(argExpr);
+ }
+
+ @Deprecated
+ public static Expression findArg(String argName) {
+ return GeneralUtils.findArg(argName);
+ }
+
+ @Deprecated
+ public static List<FieldNode> getInstanceNonPropertyFields(ClassNode cNode) {
+ return GeneralUtils.getInstanceNonPropertyFields(cNode);
+ }
+
+ @Deprecated
+ public static List<PropertyNode> getInstanceProperties(ClassNode cNode) {
+ return GeneralUtils.getInstanceProperties(cNode);
+ }
+
+ @Deprecated
+ public static List<FieldNode> getInstancePropertyFields(ClassNode cNode) {
+ return GeneralUtils.getInstancePropertyFields(cNode);
+ }
+
+ @Deprecated
+ public static List<FieldNode> getSuperNonPropertyFields(ClassNode cNode) {
+ return GeneralUtils.getSuperNonPropertyFields(cNode);
+ }
+
+ @Deprecated
+ public static List<FieldNode> getSuperPropertyFields(ClassNode cNode) {
+ return GeneralUtils.getSuperPropertyFields(cNode);
+ }
+
+ @Deprecated
+ public static boolean hasDeclaredMethod(ClassNode cNode, String name, int argsCount) {
+ return GeneralUtils.hasDeclaredMethod(cNode, name, argsCount);
+ }
+
+ @Deprecated
+ public static BooleanExpression identicalExpr(Expression self, Expression other) {
+ return GeneralUtils.sameX(self, other);
+ }
+
+ @Deprecated
+ public static BooleanExpression isInstanceOf(Expression objectExpression, ClassNode cNode) {
+ return GeneralUtils.isInstanceOfX(objectExpression, cNode);
+ }
+
+ @Deprecated
+ public static BooleanExpression isInstanceof(ClassNode cNode, Expression other) {
+ return GeneralUtils.isInstanceOfX(other, cNode);
+ }
+
+ @Deprecated
+ public static BooleanExpression isOneExpr(Expression expr) {
+ return GeneralUtils.isOneX(expr);
+ }
+
+ @Deprecated
+ public static boolean isOrImplements(ClassNode fieldType, ClassNode interfaceType) {
+ return GeneralUtils.isOrImplements(fieldType, interfaceType);
+ }
+
+ @Deprecated
+ public static BooleanExpression isTrueExpr(Expression argExpr) {
+ return GeneralUtils.isTrueX(argExpr);
+ }
+
+ @Deprecated
+ public static BooleanExpression isZeroExpr(Expression expr) {
+ return GeneralUtils.isZeroX(expr);
+ }
+
+ @Deprecated
+ public static BooleanExpression notNullExpr(Expression argExpr) {
+ return GeneralUtils.notNullX(argExpr);
+ }
+
+ @Deprecated
+ public static Statement returnFalseIfFieldNotEqual(FieldNode fNode, Expression other) {
+ return GeneralUtils.ifS(GeneralUtils.notX(GeneralUtils.hasEqualFieldX(fNode, other)), GeneralUtils.returnS(GeneralUtils.constX(Boolean.FALSE)));
+ }
+
+ @Deprecated
+ public static Statement returnFalseIfNotInstanceof(ClassNode cNode, Expression other) {
+ return GeneralUtils.ifS(GeneralUtils.notX(GeneralUtils.isInstanceOfX(other, cNode)), GeneralUtils.returnS(GeneralUtils.constX(Boolean.FALSE)));
+ }
+
+ @Deprecated
+ public static IfStatement returnFalseIfNull(Expression other) {
+ return (IfStatement) GeneralUtils.ifS(GeneralUtils.equalsNullX(other), GeneralUtils.returnS(GeneralUtils.constX(Boolean.FALSE)));
+ }
+
+ @Deprecated
+ public static Statement returnFalseIfPropertyNotEqual(PropertyNode pNode, Expression other) {
+ return GeneralUtils.ifS(GeneralUtils.notX(GeneralUtils.hasEqualPropertyX(pNode, other)), GeneralUtils.returnS(GeneralUtils.constX(Boolean.FALSE)));
+ }
+
+ @Deprecated
+ public static Statement returnFalseIfWrongType(ClassNode cNode, Expression other) {
+ return GeneralUtils.ifS(GeneralUtils.notX(GeneralUtils.hasClassX(other, cNode)), GeneralUtils.returnS(GeneralUtils.constX(Boolean.FALSE)));
+ }
+
+ @Deprecated
+ public static IfStatement returnTrueIfIdentical(Expression self, Expression other) {
+ return (IfStatement) GeneralUtils.ifS(GeneralUtils.sameX(self, other), GeneralUtils.returnS(GeneralUtils.constX(Boolean.TRUE)));
+ }
+
+ @Deprecated
+ public static Statement safeExpression(Expression fieldExpr, Expression expression) {
+ return GeneralUtils.safeExpression(fieldExpr, expression);
+ }
+
+}
diff --git a/src/main/java/org/codehaus/groovy/transform/AbstractASTTransformation.java b/src/main/java/org/codehaus/groovy/transform/AbstractASTTransformation.java
index c13c8ef..4fc13d2 100644
--- a/src/main/java/org/codehaus/groovy/transform/AbstractASTTransformation.java
+++ b/src/main/java/org/codehaus/groovy/transform/AbstractASTTransformation.java
@@ -1,494 +1,494 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.codehaus.groovy.transform;
-
-import org.apache.groovy.ast.tools.AnnotatedNodeUtils;
-import org.apache.groovy.ast.tools.MethodNodeUtils;
-import org.codehaus.groovy.GroovyBugError;
-import org.codehaus.groovy.ast.ASTNode;
-import org.codehaus.groovy.ast.AnnotatedNode;
-import org.codehaus.groovy.ast.AnnotationNode;
-import org.codehaus.groovy.ast.ClassHelper;
-import org.codehaus.groovy.ast.ClassNode;
-import org.codehaus.groovy.ast.FieldNode;
-import org.codehaus.groovy.ast.MethodNode;
-import org.codehaus.groovy.ast.PropertyNode;
-import org.codehaus.groovy.ast.expr.ClassExpression;
-import org.codehaus.groovy.ast.expr.ConstantExpression;
-import org.codehaus.groovy.ast.expr.Expression;
-import org.codehaus.groovy.ast.expr.ListExpression;
-import org.codehaus.groovy.ast.expr.VariableExpression;
-import org.codehaus.groovy.ast.tools.BeanUtils;
-import org.codehaus.groovy.ast.tools.GeneralUtils;
-import org.codehaus.groovy.ast.tools.GenericsUtils;
-import org.codehaus.groovy.control.SourceUnit;
-import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
-import org.codehaus.groovy.runtime.StringGroovyMethods;
-import org.codehaus.groovy.syntax.SyntaxException;
-import org.objectweb.asm.Opcodes;
-
-import java.lang.annotation.Retention;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-import static groovy.transform.Undefined.isUndefined;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.getInstanceNonPropertyFieldNames;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.getSuperNonPropertyFields;
-
-public abstract class AbstractASTTransformation implements Opcodes, ASTTransformation, ErrorCollecting {
- public static final ClassNode RETENTION_CLASSNODE = ClassHelper.makeWithoutCaching(Retention.class);
-
- protected SourceUnit sourceUnit;
-
- /**
- * Copies all <tt>candidateAnnotations</tt> with retention policy {@link java.lang.annotation.RetentionPolicy#RUNTIME}
- * and {@link java.lang.annotation.RetentionPolicy#CLASS}.
- * <p>
- * Annotations with {@link org.codehaus.groovy.runtime.GeneratedClosure} members are not supported for now.
- */
- protected List<AnnotationNode> copyAnnotatedNodeAnnotations(final AnnotatedNode annotatedNode, String myTypeName) {
- final List<AnnotationNode> copiedAnnotations = new ArrayList<AnnotationNode>();
- final List<AnnotationNode> notCopied = new ArrayList<AnnotationNode>();
- GeneralUtils.copyAnnotatedNodeAnnotations(annotatedNode, copiedAnnotations, notCopied);
- for (AnnotationNode annotation : notCopied) {
- addError(myTypeName + " does not support keeping Closure annotation members.", annotation);
- }
- return copiedAnnotations;
- }
-
- /**
- * If the transform is associated with a single annotation, returns a name suitable for displaying in error messages.
- *
- * @return The simple name of the annotation including the "@" or null if no such name is defined
- */
- public String getAnnotationName() {
- return null;
- }
-
- protected void init(ASTNode[] nodes, SourceUnit sourceUnit) {
- if (nodes == null || nodes.length != 2 || !(nodes[0] instanceof AnnotationNode) || !(nodes[1] instanceof AnnotatedNode)) {
- throw new GroovyBugError("Internal error: expecting [AnnotationNode, AnnotatedNode] but got: " + (nodes == null ? null : Arrays.asList(nodes)));
- }
- this.sourceUnit = sourceUnit;
- }
-
- public boolean memberHasValue(AnnotationNode node, String name, Object value) {
- final Expression member = node.getMember(name);
- return member instanceof ConstantExpression && ((ConstantExpression) member).getValue().equals(value);
- }
-
- public Object getMemberValue(AnnotationNode node, String name) {
- final Expression member = node.getMember(name);
- if (member instanceof ConstantExpression) return ((ConstantExpression) member).getValue();
- return null;
- }
-
- public static String getMemberStringValue(AnnotationNode node, String name, String defaultValue) {
- final Expression member = node.getMember(name);
- if (member instanceof ConstantExpression) {
- Object result = ((ConstantExpression) member).getValue();
- if (result instanceof String && isUndefined((String) result)) result = null;
- if (result != null) return result.toString();
- }
- return defaultValue;
- }
-
- public static String getMemberStringValue(AnnotationNode node, String name) {
- return getMemberStringValue(node, name, null);
- }
-
- public int getMemberIntValue(AnnotationNode node, String name) {
- Object value = getMemberValue(node, name);
- if (value instanceof Integer) {
- return (Integer) value;
- }
- return 0;
- }
-
- public ClassNode getMemberClassValue(AnnotationNode node, String name) {
- return getMemberClassValue(node, name, null);
- }
-
- public ClassNode getMemberClassValue(AnnotationNode node, String name, ClassNode defaultValue) {
- final Expression member = node.getMember(name);
- if (member != null) {
- if (member instanceof ClassExpression) {
- if (!isUndefined(member.getType())) return member.getType();
- } else if (member instanceof VariableExpression) {
- addError("Error expecting to find class value for '" + name + "' but found variable: " + member.getText() + ". Missing import?", node);
- return null;
- } else if (member instanceof ConstantExpression) {
- addError("Error expecting to find class value for '" + name + "' but found constant: " + member.getText() + "!", node);
- return null;
- }
- }
- return defaultValue;
- }
-
- public static List<String> getMemberStringList(AnnotationNode anno, String name) {
- Expression expr = anno.getMember(name);
- if (expr == null) {
- return null;
- }
- if (expr instanceof ListExpression) {
- final ListExpression listExpression = (ListExpression) expr;
- if (isUndefinedMarkerList(listExpression)) {
- return null;
- }
-
- return getValueStringList(listExpression);
- }
- return tokenize(getMemberStringValue(anno, name));
- }
-
- private static boolean isUndefinedMarkerList(ListExpression listExpression) {
- if (listExpression.getExpressions().size() != 1) return false;
- Expression itemExpr = listExpression.getExpression(0);
- if (itemExpr == null) return false;
- if (itemExpr instanceof ConstantExpression) {
- Object value = ((ConstantExpression) itemExpr).getValue();
- if (value instanceof String && isUndefined((String)value)) return true;
- } else if (itemExpr instanceof ClassExpression && isUndefined(itemExpr.getType())) {
- return true;
- }
- return false;
- }
-
- @Deprecated
- public static List<String> getMemberList(AnnotationNode anno, String name) {
- List<String> list;
- Expression expr = anno.getMember(name);
- if (expr instanceof ListExpression) {
- final ListExpression listExpression = (ListExpression) expr;
- list = getValueStringList(listExpression);
- } else {
- list = tokenize(getMemberStringValue(anno, name));
- }
- return list;
- }
-
- private static List<String> getValueStringList(ListExpression listExpression) {
- List<String> list = new ArrayList<String>();
- for (Expression itemExpr : listExpression.getExpressions()) {
- if (itemExpr instanceof ConstantExpression) {
- Object value = ((ConstantExpression) itemExpr).getValue();
- if (value != null) list.add(value.toString());
- }
- }
- return list;
- }
-
- @Deprecated
- public List<ClassNode> getClassList(AnnotationNode anno, String name) {
- List<ClassNode> list = new ArrayList<ClassNode>();
- Expression expr = anno.getMember(name);
- if (expr instanceof ListExpression) {
- final ListExpression listExpression = (ListExpression) expr;
- list = getTypeList(listExpression);
- } else if (expr instanceof ClassExpression) {
- ClassNode cn = expr.getType();
- if (cn != null) list.add(cn);
- }
- return list;
- }
-
- public List<ClassNode> getMemberClassList(AnnotationNode anno, String name) {
- List<ClassNode> list = new ArrayList<ClassNode>();
- Expression expr = anno.getMember(name);
- if (expr == null) {
- return null;
- }
- if (expr instanceof ListExpression) {
- final ListExpression listExpression = (ListExpression) expr;
- if (isUndefinedMarkerList(listExpression)) {
- return null;
- }
- list = getTypeList(listExpression);
- } else if (expr instanceof ClassExpression) {
- ClassNode cn = expr.getType();
- if (isUndefined(cn)) return null;
- if (cn != null) list.add(cn);
- }
- return list;
- }
-
- private static List<ClassNode> getTypeList(ListExpression listExpression) {
- List<ClassNode> list = new ArrayList<ClassNode>();
- for (Expression itemExpr : listExpression.getExpressions()) {
- if (itemExpr instanceof ClassExpression) {
- ClassNode cn = itemExpr.getType();
- if (cn != null) list.add(cn);
- }
- }
- return list;
- }
-
- public void addError(String msg, ASTNode expr) {
- sourceUnit.getErrorCollector().addErrorAndContinue(new SyntaxErrorMessage(
- new SyntaxException(msg + '\n', expr.getLineNumber(), expr.getColumnNumber(),
- expr.getLastLineNumber(), expr.getLastColumnNumber()),
- sourceUnit)
- );
- }
-
- protected boolean checkNotInterface(ClassNode cNode, String annotationName) {
- if (cNode.isInterface()) {
- addError("Error processing interface '" + cNode.getName() + "'. " +
- annotationName + " not allowed for interfaces.", cNode);
- return false;
- }
- return true;
- }
-
- public boolean hasAnnotation(ClassNode node, ClassNode annotation) {
- return AnnotatedNodeUtils.hasAnnotation(node, annotation);
- }
-
- public static List<String> tokenize(String rawExcludes) {
- return rawExcludes == null ? new ArrayList<String>() : StringGroovyMethods.tokenize(rawExcludes, ", ");
- }
-
- public static boolean deemedInternalName(String name) {
- return name.contains("$");
- }
-
- public static boolean shouldSkipUndefinedAware(String name, List<String> excludes, List<String> includes) {
- return shouldSkipUndefinedAware(name, excludes, includes, false);
- }
-
- public static boolean shouldSkipUndefinedAware(String name, List<String> excludes, List<String> includes, boolean allNames) {
- return (excludes != null && excludes.contains(name)) ||
- (!allNames && deemedInternalName(name)) ||
- (includes != null && !includes.contains(name));
- }
-
- public static boolean shouldSkip(String name, List<String> excludes, List<String> includes) {
- return shouldSkip(name, excludes, includes, false);
- }
-
- public static boolean shouldSkip(String name, List<String> excludes, List<String> includes, boolean allNames) {
- return (excludes != null && excludes.contains(name)) ||
- (!allNames && deemedInternalName(name)) ||
- (includes != null && !includes.isEmpty() && !includes.contains(name));
- }
-
- @Deprecated
- public static boolean shouldSkipOnDescriptor(boolean checkReturn, Map genericsSpec, MethodNode mNode, List<ClassNode> excludeTypes, List<ClassNode> includeTypes) {
- String descriptor = mNode.getTypeDescriptor();
- String descriptorNoReturn = MethodNodeUtils.methodDescriptorWithoutReturnType(mNode);
- for (ClassNode cn : excludeTypes) {
- List<ClassNode> remaining = new LinkedList<ClassNode>();
- remaining.add(cn);
- Map updatedGenericsSpec = new HashMap(genericsSpec);
- while (!remaining.isEmpty()) {
- ClassNode next = remaining.remove(0);
- if (!next.equals(ClassHelper.OBJECT_TYPE)) {
- updatedGenericsSpec = GenericsUtils.createGenericsSpec(next, updatedGenericsSpec);
- for (MethodNode mn : next.getMethods()) {
- MethodNode correctedMethodNode = GenericsUtils.correctToGenericsSpec(updatedGenericsSpec, mn);
- if (checkReturn) {
- String md = correctedMethodNode.getTypeDescriptor();
- if (md.equals(descriptor)) return true;
- } else {
- String md = MethodNodeUtils.methodDescriptorWithoutReturnType(correctedMethodNode);
- if (md.equals(descriptorNoReturn)) return true;
- }
- }
- remaining.addAll(Arrays.asList(next.getInterfaces()));
- }
- }
- }
- if (includeTypes.isEmpty()) return false;
- for (ClassNode cn : includeTypes) {
- List<ClassNode> remaining = new LinkedList<ClassNode>();
- remaining.add(cn);
- Map updatedGenericsSpec = new HashMap(genericsSpec);
- while (!remaining.isEmpty()) {
- ClassNode next = remaining.remove(0);
- if (!next.equals(ClassHelper.OBJECT_TYPE)) {
- updatedGenericsSpec = GenericsUtils.createGenericsSpec(next, updatedGenericsSpec);
- for (MethodNode mn : next.getMethods()) {
- MethodNode correctedMethodNode = GenericsUtils.correctToGenericsSpec(updatedGenericsSpec, mn);
- if (checkReturn) {
- String md = correctedMethodNode.getTypeDescriptor();
- if (md.equals(descriptor)) return false;
- } else {
- String md = MethodNodeUtils.methodDescriptorWithoutReturnType(correctedMethodNode);
- if (md.equals(descriptorNoReturn)) return false;
- }
- }
- remaining.addAll(Arrays.asList(next.getInterfaces()));
- }
- }
- }
- return true;
- }
- public static boolean shouldSkipOnDescriptorUndefinedAware(boolean checkReturn, Map genericsSpec, MethodNode mNode,
- List<ClassNode> excludeTypes, List<ClassNode> includeTypes) {
- String descriptor = mNode.getTypeDescriptor();
- String descriptorNoReturn = MethodNodeUtils.methodDescriptorWithoutReturnType(mNode);
- if (excludeTypes != null) {
- for (ClassNode cn : excludeTypes) {
- List<ClassNode> remaining = new LinkedList<ClassNode>();
- remaining.add(cn);
- Map updatedGenericsSpec = new HashMap(genericsSpec);
- while (!remaining.isEmpty()) {
- ClassNode next = remaining.remove(0);
- if (!next.equals(ClassHelper.OBJECT_TYPE)) {
- updatedGenericsSpec = GenericsUtils.createGenericsSpec(next, updatedGenericsSpec);
- for (MethodNode mn : next.getMethods()) {
- MethodNode correctedMethodNode = GenericsUtils.correctToGenericsSpec(updatedGenericsSpec, mn);
- if (checkReturn) {
- String md = correctedMethodNode.getTypeDescriptor();
- if (md.equals(descriptor)) return true;
- } else {
- String md = MethodNodeUtils.methodDescriptorWithoutReturnType(correctedMethodNode);
- if (md.equals(descriptorNoReturn)) return true;
- }
- }
- remaining.addAll(Arrays.asList(next.getInterfaces()));
- }
- }
- }
- }
- if (includeTypes == null) return false;
- for (ClassNode cn : includeTypes) {
- List<ClassNode> remaining = new LinkedList<ClassNode>();
- remaining.add(cn);
- Map updatedGenericsSpec = new HashMap(genericsSpec);
- while (!remaining.isEmpty()) {
- ClassNode next = remaining.remove(0);
- if (!next.equals(ClassHelper.OBJECT_TYPE)) {
- updatedGenericsSpec = GenericsUtils.createGenericsSpec(next, updatedGenericsSpec);
- for (MethodNode mn : next.getMethods()) {
- MethodNode correctedMethodNode = GenericsUtils.correctToGenericsSpec(updatedGenericsSpec, mn);
- if (checkReturn) {
- String md = correctedMethodNode.getTypeDescriptor();
- if (md.equals(descriptor)) return false;
- } else {
- String md = MethodNodeUtils.methodDescriptorWithoutReturnType(correctedMethodNode);
- if (md.equals(descriptorNoReturn)) return false;
- }
- }
- remaining.addAll(Arrays.asList(next.getInterfaces()));
- }
- }
- }
- return true;
- }
-
- @Deprecated
- protected boolean checkIncludeExclude(AnnotationNode node, List<String> excludes, List<String> includes, String typeName) {
- if (includes != null && !includes.isEmpty() && excludes != null && !excludes.isEmpty()) {
- addError("Error during " + typeName + " processing: Only one of 'includes' and 'excludes' should be supplied not both.", node);
- return false;
- }
- return true;
- }
-
- protected boolean checkIncludeExcludeUndefinedAware(AnnotationNode node, List<String> excludes, List<String> includes, String typeName) {
- if (includes != null && excludes != null && !excludes.isEmpty()) {
- addError("Error during " + typeName + " processing: Only one of 'includes' and 'excludes' should be supplied not both.", node);
- return false;
- }
- return true;
- }
-
- @Deprecated
- protected void checkIncludeExclude(AnnotationNode node, List<String> excludes, List<String> includes, List<ClassNode> excludeTypes, List<ClassNode> includeTypes, String typeName) {
- int found = 0;
- if (includes != null && !includes.isEmpty()) found++;
- if (excludes != null && !excludes.isEmpty()) found++;
- if (includeTypes != null && !includeTypes.isEmpty()) found++;
- if (excludeTypes != null && !excludeTypes.isEmpty()) found++;
- if (found > 1) {
- addError("Error during " + typeName + " processing: Only one of 'includes', 'excludes', 'includeTypes' and 'excludeTypes' should be supplied.", node);
- }
- }
-
- protected void checkIncludeExcludeUndefinedAware(AnnotationNode node, List<String> excludes, List<String> includes,
- List<ClassNode> excludeTypes, List<ClassNode> includeTypes, String typeName) {
- int found = 0;
- if (includes != null) found++;
- if (excludes != null && !excludes.isEmpty()) found++;
- if (includeTypes != null) found++;
- if (excludeTypes != null && !excludeTypes.isEmpty()) found++;
- if (found > 1) {
- addError("Error during " + typeName + " processing: Only one of 'includes', 'excludes', 'includeTypes' and 'excludeTypes' should be supplied.", node);
- }
- }
-
- public boolean checkPropertyList(ClassNode cNode, List<String> propertyNameList, String listName, AnnotationNode anno, String typeName, boolean includeFields) {
- return checkPropertyList(cNode, propertyNameList, listName, anno, typeName, includeFields, false, false);
- }
-
- public boolean checkPropertyList(ClassNode cNode, List<String> propertyNameList, String listName, AnnotationNode anno, String typeName, boolean includeFields, boolean includeSuperProperties, boolean allProperties) {
- return checkPropertyList(cNode, propertyNameList, listName, anno, typeName, includeFields, includeSuperProperties, allProperties, false, false);
- }
-
- public boolean checkPropertyList(ClassNode cNode, List<String> propertyNameList, String listName, AnnotationNode anno, String typeName, boolean includeFields, boolean includeSuperProperties, boolean allProperties, boolean includeSuperFields, boolean includeStatic) {
- if (propertyNameList == null || propertyNameList.isEmpty()) {
- return true;
- }
- final List<String> pNames = new ArrayList<String>();
- for (PropertyNode pNode : BeanUtils.getAllProperties(cNode, includeSuperProperties, includeStatic, allProperties)) {
- pNames.add(pNode.getField().getName());
- }
- boolean result = true;
- if (includeFields || includeSuperFields) {
- final List<String> fNames = new ArrayList<String>();
- if (includeFields) {
- fNames.addAll(getInstanceNonPropertyFieldNames(cNode));
- }
- if (includeSuperFields) {
- List<FieldNode> superNonPropertyFields = getSuperNonPropertyFields(cNode.getSuperClass());
- for (FieldNode fn : superNonPropertyFields) {
- fNames.add(fn.getName());
- }
- }
- for (String pName : propertyNameList) {
- if (!pNames.contains(pName) && !fNames.contains(pName)) {
- addError("Error during " + typeName + " processing: '" + listName + "' property or field '" + pName + "' does not exist.", anno);
- result = false;
- }
- }
- } else {
- for (String pName : propertyNameList) {
- if (!pNames.contains(pName)) {
- addError("Error during " + typeName + " processing: '" + listName + "' property '" + pName + "' does not exist.", anno);
- result = false;
- }
- }
- }
- return result;
- }
-
- /**
- * @deprecated use GenericsUtils#nonGeneric
- */
- @Deprecated
- public static ClassNode nonGeneric(ClassNode type) {
- return GenericsUtils.nonGeneric(type);
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.codehaus.groovy.transform;
+
+import org.apache.groovy.ast.tools.AnnotatedNodeUtils;
+import org.apache.groovy.ast.tools.MethodNodeUtils;
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.AnnotatedNode;
+import org.codehaus.groovy.ast.AnnotationNode;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.PropertyNode;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.ListExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.tools.BeanUtils;
+import org.codehaus.groovy.ast.tools.GeneralUtils;
+import org.codehaus.groovy.ast.tools.GenericsUtils;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
+import org.codehaus.groovy.runtime.StringGroovyMethods;
+import org.codehaus.groovy.syntax.SyntaxException;
+import org.objectweb.asm.Opcodes;
+
+import java.lang.annotation.Retention;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import static groovy.transform.Undefined.isUndefined;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.getInstanceNonPropertyFieldNames;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.getSuperNonPropertyFields;
+
+public abstract class AbstractASTTransformation implements Opcodes, ASTTransformation, ErrorCollecting {
+ public static final ClassNode RETENTION_CLASSNODE = ClassHelper.makeWithoutCaching(Retention.class);
+
+ protected SourceUnit sourceUnit;
+
+ /**
+ * Copies all <tt>candidateAnnotations</tt> with retention policy {@link java.lang.annotation.RetentionPolicy#RUNTIME}
+ * and {@link java.lang.annotation.RetentionPolicy#CLASS}.
+ * <p>
+ * Annotations with {@link org.codehaus.groovy.runtime.GeneratedClosure} members are not supported for now.
+ */
+ protected List<AnnotationNode> copyAnnotatedNodeAnnotations(final AnnotatedNode annotatedNode, String myTypeName) {
+ final List<AnnotationNode> copiedAnnotations = new ArrayList<AnnotationNode>();
+ final List<AnnotationNode> notCopied = new ArrayList<AnnotationNode>();
+ GeneralUtils.copyAnnotatedNodeAnnotations(annotatedNode, copiedAnnotations, notCopied);
+ for (AnnotationNode annotation : notCopied) {
+ addError(myTypeName + " does not support keeping Closure annotation members.", annotation);
+ }
+ return copiedAnnotations;
+ }
+
+ /**
+ * If the transform is associated with a single annotation, returns a name suitable for displaying in error messages.
+ *
+ * @return The simple name of the annotation including the "@" or null if no such name is defined
+ */
+ public String getAnnotationName() {
+ return null;
+ }
+
+ protected void init(ASTNode[] nodes, SourceUnit sourceUnit) {
+ if (nodes == null || nodes.length != 2 || !(nodes[0] instanceof AnnotationNode) || !(nodes[1] instanceof AnnotatedNode)) {
+ throw new GroovyBugError("Internal error: expecting [AnnotationNode, AnnotatedNode] but got: " + (nodes == null ? null : Arrays.asList(nodes)));
+ }
+ this.sourceUnit = sourceUnit;
+ }
+
+ public boolean memberHasValue(AnnotationNode node, String name, Object value) {
+ final Expression member = node.getMember(name);
+ return member instanceof ConstantExpression && ((ConstantExpression) member).getValue().equals(value);
+ }
+
+ public Object getMemberValue(AnnotationNode node, String name) {
+ final Expression member = node.getMember(name);
+ if (member instanceof ConstantExpression) return ((ConstantExpression) member).getValue();
+ return null;
+ }
+
+ public static String getMemberStringValue(AnnotationNode node, String name, String defaultValue) {
+ final Expression member = node.getMember(name);
+ if (member instanceof ConstantExpression) {
+ Object result = ((ConstantExpression) member).getValue();
+ if (result instanceof String && isUndefined((String) result)) result = null;
+ if (result != null) return result.toString();
+ }
+ return defaultValue;
+ }
+
+ public static String getMemberStringValue(AnnotationNode node, String name) {
+ return getMemberStringValue(node, name, null);
+ }
+
+ public int getMemberIntValue(AnnotationNode node, String name) {
+ Object value = getMemberValue(node, name);
+ if (value instanceof Integer) {
+ return (Integer) value;
+ }
+ return 0;
+ }
+
+ public ClassNode getMemberClassValue(AnnotationNode node, String name) {
+ return getMemberClassValue(node, name, null);
+ }
+
+ public ClassNode getMemberClassValue(AnnotationNode node, String name, ClassNode defaultValue) {
+ final Expression member = node.getMember(name);
+ if (member != null) {
+ if (member instanceof ClassExpression) {
+ if (!isUndefined(member.getType())) return member.getType();
+ } else if (member instanceof VariableExpression) {
+ addError("Error expecting to find class value for '" + name + "' but found variable: " + member.getText() + ". Missing import?", node);
+ return null;
+ } else if (member instanceof ConstantExpression) {
+ addError("Error expecting to find class value for '" + name + "' but found constant: " + member.getText() + "!", node);
+ return null;
+ }
+ }
+ return defaultValue;
+ }
+
+ public static List<String> getMemberStringList(AnnotationNode anno, String name) {
+ Expression expr = anno.getMember(name);
+ if (expr == null) {
+ return null;
+ }
+ if (expr instanceof ListExpression) {
+ final ListExpression listExpression = (ListExpression) expr;
+ if (isUndefinedMarkerList(listExpression)) {
+ return null;
+ }
+
+ return getValueStringList(listExpression);
+ }
+ return tokenize(getMemberStringValue(anno, name));
+ }
+
+ private static boolean isUndefinedMarkerList(ListExpression listExpression) {
+ if (listExpression.getExpressions().size() != 1) return false;
+ Expression itemExpr = listExpression.getExpression(0);
+ if (itemExpr == null) return false;
+ if (itemExpr instanceof ConstantExpression) {
+ Object value = ((ConstantExpression) itemExpr).getValue();
+ if (value instanceof String && isUndefined((String)value)) return true;
+ } else if (itemExpr instanceof ClassExpression && isUndefined(itemExpr.getType())) {
+ return true;
+ }
+ return false;
+ }
+
+ @Deprecated
+ public static List<String> getMemberList(AnnotationNode anno, String name) {
+ List<String> list;
+ Expression expr = anno.getMember(name);
+ if (expr instanceof ListExpression) {
+ final ListExpression listExpression = (ListExpression) expr;
+ list = getValueStringList(listExpression);
+ } else {
+ list = tokenize(getMemberStringValue(anno, name));
+ }
+ return list;
+ }
+
+ private static List<String> getValueStringList(ListExpression listExpression) {
+ List<String> list = new ArrayList<String>();
+ for (Expression itemExpr : listExpression.getExpressions()) {
+ if (itemExpr instanceof ConstantExpression) {
+ Object value = ((ConstantExpression) itemExpr).getValue();
+ if (value != null) list.add(value.toString());
+ }
+ }
+ return list;
+ }
+
+ @Deprecated
+ public List<ClassNode> getClassList(AnnotationNode anno, String name) {
+ List<ClassNode> list = new ArrayList<ClassNode>();
+ Expression expr = anno.getMember(name);
+ if (expr instanceof ListExpression) {
+ final ListExpression listExpression = (ListExpression) expr;
+ list = getTypeList(listExpression);
+ } else if (expr instanceof ClassExpression) {
+ ClassNode cn = expr.getType();
+ if (cn != null) list.add(cn);
+ }
+ return list;
+ }
+
+ public List<ClassNode> getMemberClassList(AnnotationNode anno, String name) {
+ List<ClassNode> list = new ArrayList<ClassNode>();
+ Expression expr = anno.getMember(name);
+ if (expr == null) {
+ return null;
+ }
+ if (expr instanceof ListExpression) {
+ final ListExpression listExpression = (ListExpression) expr;
+ if (isUndefinedMarkerList(listExpression)) {
+ return null;
+ }
+ list = getTypeList(listExpression);
+ } else if (expr instanceof ClassExpression) {
+ ClassNode cn = expr.getType();
+ if (isUndefined(cn)) return null;
+ if (cn != null) list.add(cn);
+ }
+ return list;
+ }
+
+ private static List<ClassNode> getTypeList(ListExpression listExpression) {
+ List<ClassNode> list = new ArrayList<ClassNode>();
+ for (Expression itemExpr : listExpression.getExpressions()) {
+ if (itemExpr instanceof ClassExpression) {
+ ClassNode cn = itemExpr.getType();
+ if (cn != null) list.add(cn);
+ }
+ }
+ return list;
+ }
+
+ public void addError(String msg, ASTNode expr) {
+ sourceUnit.getErrorCollector().addErrorAndContinue(new SyntaxErrorMessage(
+ new SyntaxException(msg + '\n', expr.getLineNumber(), expr.getColumnNumber(),
+ expr.getLastLineNumber(), expr.getLastColumnNumber()),
+ sourceUnit)
+ );
+ }
+
+ protected boolean checkNotInterface(ClassNode cNode, String annotationName) {
+ if (cNode.isInterface()) {
+ addError("Error processing interface '" + cNode.getName() + "'. " +
+ annotationName + " not allowed for interfaces.", cNode);
+ return false;
+ }
+ return true;
+ }
+
+ public boolean hasAnnotation(ClassNode node, ClassNode annotation) {
+ return AnnotatedNodeUtils.hasAnnotation(node, annotation);
+ }
+
+ public static List<String> tokenize(String rawExcludes) {
+ return rawExcludes == null ? new ArrayList<String>() : StringGroovyMethods.tokenize(rawExcludes, ", ");
+ }
+
+ public static boolean deemedInternalName(String name) {
+ return name.contains("$");
+ }
+
+ public static boolean shouldSkipUndefinedAware(String name, List<String> excludes, List<String> includes) {
+ return shouldSkipUndefinedAware(name, excludes, includes, false);
+ }
+
+ public static boolean shouldSkipUndefinedAware(String name, List<String> excludes, List<String> includes, boolean allNames) {
+ return (excludes != null && excludes.contains(name)) ||
+ (!allNames && deemedInternalName(name)) ||
+ (includes != null && !includes.contains(name));
+ }
+
+ public static boolean shouldSkip(String name, List<String> excludes, List<String> includes) {
+ return shouldSkip(name, excludes, includes, false);
+ }
+
+ public static boolean shouldSkip(String name, List<String> excludes, List<String> includes, boolean allNames) {
+ return (excludes != null && excludes.contains(name)) ||
+ (!allNames && deemedInternalName(name)) ||
+ (includes != null && !includes.isEmpty() && !includes.contains(name));
+ }
+
+ @Deprecated
+ public static boolean shouldSkipOnDescriptor(boolean checkReturn, Map genericsSpec, MethodNode mNode, List<ClassNode> excludeTypes, List<ClassNode> includeTypes) {
+ String descriptor = mNode.getTypeDescriptor();
+ String descriptorNoReturn = MethodNodeUtils.methodDescriptorWithoutReturnType(mNode);
+ for (ClassNode cn : excludeTypes) {
+ List<ClassNode> remaining = new LinkedList<ClassNode>();
+ remaining.add(cn);
+ Map updatedGenericsSpec = new HashMap(genericsSpec);
+ while (!remaining.isEmpty()) {
+ ClassNode next = remaining.remove(0);
+ if (!next.equals(ClassHelper.OBJECT_TYPE)) {
+ updatedGenericsSpec = GenericsUtils.createGenericsSpec(next, updatedGenericsSpec);
+ for (MethodNode mn : next.getMethods()) {
+ MethodNode correctedMethodNode = GenericsUtils.correctToGenericsSpec(updatedGenericsSpec, mn);
+ if (checkReturn) {
+ String md = correctedMethodNode.getTypeDescriptor();
+ if (md.equals(descriptor)) return true;
+ } else {
+ String md = MethodNodeUtils.methodDescriptorWithoutReturnType(correctedMethodNode);
+ if (md.equals(descriptorNoReturn)) return true;
+ }
+ }
+ remaining.addAll(Arrays.asList(next.getInterfaces()));
+ }
+ }
+ }
+ if (includeTypes.isEmpty()) return false;
+ for (ClassNode cn : includeTypes) {
+ List<ClassNode> remaining = new LinkedList<ClassNode>();
+ remaining.add(cn);
+ Map updatedGenericsSpec = new HashMap(genericsSpec);
+ while (!remaining.isEmpty()) {
+ ClassNode next = remaining.remove(0);
+ if (!next.equals(ClassHelper.OBJECT_TYPE)) {
+ updatedGenericsSpec = GenericsUtils.createGenericsSpec(next, updatedGenericsSpec);
+ for (MethodNode mn : next.getMethods()) {
+ MethodNode correctedMethodNode = GenericsUtils.correctToGenericsSpec(updatedGenericsSpec, mn);
+ if (checkReturn) {
+ String md = correctedMethodNode.getTypeDescriptor();
+ if (md.equals(descriptor)) return false;
+ } else {
+ String md = MethodNodeUtils.methodDescriptorWithoutReturnType(correctedMethodNode);
+ if (md.equals(descriptorNoReturn)) return false;
+ }
+ }
+ remaining.addAll(Arrays.asList(next.getInterfaces()));
+ }
+ }
+ }
+ return true;
+ }
+ public static boolean shouldSkipOnDescriptorUndefinedAware(boolean checkReturn, Map genericsSpec, MethodNode mNode,
+ List<ClassNode> excludeTypes, List<ClassNode> includeTypes) {
+ String descriptor = mNode.getTypeDescriptor();
+ String descriptorNoReturn = MethodNodeUtils.methodDescriptorWithoutReturnType(mNode);
+ if (excludeTypes != null) {
+ for (ClassNode cn : excludeTypes) {
+ List<ClassNode> remaining = new LinkedList<ClassNode>();
+ remaining.add(cn);
+ Map updatedGenericsSpec = new HashMap(genericsSpec);
+ while (!remaining.isEmpty()) {
+ ClassNode next = remaining.remove(0);
+ if (!next.equals(ClassHelper.OBJECT_TYPE)) {
+ updatedGenericsSpec = GenericsUtils.createGenericsSpec(next, updatedGenericsSpec);
+ for (MethodNode mn : next.getMethods()) {
+ MethodNode correctedMethodNode = GenericsUtils.correctToGenericsSpec(updatedGenericsSpec, mn);
+ if (checkReturn) {
+ String md = correctedMethodNode.getTypeDescriptor();
+ if (md.equals(descriptor)) return true;
+ } else {
+ String md = MethodNodeUtils.methodDescriptorWithoutReturnType(correctedMethodNode);
+ if (md.equals(descriptorNoReturn)) return true;
+ }
+ }
+ remaining.addAll(Arrays.asList(next.getInterfaces()));
+ }
+ }
+ }
+ }
+ if (includeTypes == null) return false;
+ for (ClassNode cn : includeTypes) {
+ List<ClassNode> remaining = new LinkedList<ClassNode>();
+ remaining.add(cn);
+ Map updatedGenericsSpec = new HashMap(genericsSpec);
+ while (!remaining.isEmpty()) {
+ ClassNode next = remaining.remove(0);
+ if (!next.equals(ClassHelper.OBJECT_TYPE)) {
+ updatedGenericsSpec = GenericsUtils.createGenericsSpec(next, updatedGenericsSpec);
+ for (MethodNode mn : next.getMethods()) {
+ MethodNode correctedMethodNode = GenericsUtils.correctToGenericsSpec(updatedGenericsSpec, mn);
+ if (checkReturn) {
+ String md = correctedMethodNode.getTypeDescriptor();
+ if (md.equals(descriptor)) return false;
+ } else {
+ String md = MethodNodeUtils.methodDescriptorWithoutReturnType(correctedMethodNode);
+ if (md.equals(descriptorNoReturn)) return false;
+ }
+ }
+ remaining.addAll(Arrays.asList(next.getInterfaces()));
+ }
+ }
+ }
+ return true;
+ }
+
+ @Deprecated
+ protected boolean checkIncludeExclude(AnnotationNode node, List<String> excludes, List<String> includes, String typeName) {
+ if (includes != null && !includes.isEmpty() && excludes != null && !excludes.isEmpty()) {
+ addError("Error during " + typeName + " processing: Only one of 'includes' and 'excludes' should be supplied not both.", node);
+ return false;
+ }
+ return true;
+ }
+
+ protected boolean checkIncludeExcludeUndefinedAware(AnnotationNode node, List<String> excludes, List<String> includes, String typeName) {
+ if (includes != null && excludes != null && !excludes.isEmpty()) {
+ addError("Error during " + typeName + " processing: Only one of 'includes' and 'excludes' should be supplied not both.", node);
+ return false;
+ }
+ return true;
+ }
+
+ @Deprecated
+ protected void checkIncludeExclude(AnnotationNode node, List<String> excludes, List<String> includes, List<ClassNode> excludeTypes, List<ClassNode> includeTypes, String typeName) {
+ int found = 0;
+ if (includes != null && !includes.isEmpty()) found++;
+ if (excludes != null && !excludes.isEmpty()) found++;
+ if (includeTypes != null && !includeTypes.isEmpty()) found++;
+ if (excludeTypes != null && !excludeTypes.isEmpty()) found++;
+ if (found > 1) {
+ addError("Error during " + typeName + " processing: Only one of 'includes', 'excludes', 'includeTypes' and 'excludeTypes' should be supplied.", node);
+ }
+ }
+
+ protected void checkIncludeExcludeUndefinedAware(AnnotationNode node, List<String> excludes, List<String> includes,
+ List<ClassNode> excludeTypes, List<ClassNode> includeTypes, String typeName) {
+ int found = 0;
+ if (includes != null) found++;
+ if (excludes != null && !excludes.isEmpty()) found++;
+ if (includeTypes != null) found++;
+ if (excludeTypes != null && !excludeTypes.isEmpty()) found++;
+ if (found > 1) {
+ addError("Error during " + typeName + " processing: Only one of 'includes', 'excludes', 'includeTypes' and 'excludeTypes' should be supplied.", node);
+ }
+ }
+
+ public boolean checkPropertyList(ClassNode cNode, List<String> propertyNameList, String listName, AnnotationNode anno, String typeName, boolean includeFields) {
+ return checkPropertyList(cNode, propertyNameList, listName, anno, typeName, includeFields, false, false);
+ }
+
+ public boolean checkPropertyList(ClassNode cNode, List<String> propertyNameList, String listName, AnnotationNode anno, String typeName, boolean includeFields, boolean includeSuperProperties, boolean allProperties) {
+ return checkPropertyList(cNode, propertyNameList, listName, anno, typeName, includeFields, includeSuperProperties, allProperties, false, false);
+ }
+
+ public boolean checkPropertyList(ClassNode cNode, List<String> propertyNameList, String listName, AnnotationNode anno, String typeName, boolean includeFields, boolean includeSuperProperties, boolean allProperties, boolean includeSuperFields, boolean includeStatic) {
+ if (propertyNameList == null || propertyNameList.isEmpty()) {
+ return true;
+ }
+ final List<String> pNames = new ArrayList<String>();
+ for (PropertyNode pNode : BeanUtils.getAllProperties(cNode, includeSuperProperties, includeStatic, allProperties)) {
+ pNames.add(pNode.getField().getName());
+ }
+ boolean result = true;
+ if (includeFields || includeSuperFields) {
+ final List<String> fNames = new ArrayList<String>();
+ if (includeFields) {
+ fNames.addAll(getInstanceNonPropertyFieldNames(cNode));
+ }
+ if (includeSuperFields) {
+ List<FieldNode> superNonPropertyFields = getSuperNonPropertyFields(cNode.getSuperClass());
+ for (FieldNode fn : superNonPropertyFields) {
+ fNames.add(fn.getName());
+ }
+ }
+ for (String pName : propertyNameList) {
+ if (!pNames.contains(pName) && !fNames.contains(pName)) {
+ addError("Error during " + typeName + " processing: '" + listName + "' property or field '" + pName + "' does not exist.", anno);
+ result = false;
+ }
+ }
+ } else {
+ for (String pName : propertyNameList) {
+ if (!pNames.contains(pName)) {
+ addError("Error during " + typeName + " processing: '" + listName + "' property '" + pName + "' does not exist.", anno);
+ result = false;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * @deprecated use GenericsUtils#nonGeneric
+ */
+ @Deprecated
+ public static ClassNode nonGeneric(ClassNode type) {
+ return GenericsUtils.nonGeneric(type);
+ }
+
+}
diff --git a/src/main/java/org/codehaus/groovy/transform/FieldASTTransformation.java b/src/main/java/org/codehaus/groovy/transform/FieldASTTransformation.java
index ede65fd..4deb112 100644
--- a/src/main/java/org/codehaus/groovy/transform/FieldASTTransformation.java
+++ b/src/main/java/org/codehaus/groovy/transform/FieldASTTransformation.java
@@ -1,292 +1,292 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.codehaus.groovy.transform;
-
-import groovy.cli.Option;
-import groovy.lang.Lazy;
-import groovy.transform.Field;
-import org.codehaus.groovy.GroovyBugError;
-import org.codehaus.groovy.ast.ASTNode;
-import org.codehaus.groovy.ast.AnnotatedNode;
-import org.codehaus.groovy.ast.AnnotationNode;
-import org.codehaus.groovy.ast.ClassCodeExpressionTransformer;
-import org.codehaus.groovy.ast.ClassHelper;
-import org.codehaus.groovy.ast.ClassNode;
-import org.codehaus.groovy.ast.ConstructorNode;
-import org.codehaus.groovy.ast.FieldNode;
-import org.codehaus.groovy.ast.MethodNode;
-import org.codehaus.groovy.ast.Parameter;
-import org.codehaus.groovy.ast.Variable;
-import org.codehaus.groovy.ast.VariableScope;
-import org.codehaus.groovy.ast.expr.ArgumentListExpression;
-import org.codehaus.groovy.ast.expr.ClosureExpression;
-import org.codehaus.groovy.ast.expr.ConstantExpression;
-import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
-import org.codehaus.groovy.ast.expr.DeclarationExpression;
-import org.codehaus.groovy.ast.expr.Expression;
-import org.codehaus.groovy.ast.expr.TupleExpression;
-import org.codehaus.groovy.ast.expr.VariableExpression;
-import org.codehaus.groovy.ast.stmt.ExpressionStatement;
-import org.codehaus.groovy.classgen.VariableScopeVisitor;
-import org.codehaus.groovy.control.CompilePhase;
-import org.codehaus.groovy.control.SourceUnit;
-import org.objectweb.asm.Opcodes;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.List;
-
-import static org.apache.groovy.ast.tools.ClassNodeUtils.addGeneratedConstructor;
-import static org.apache.groovy.util.BeanUtils.capitalize;
-import static org.codehaus.groovy.ast.ClassHelper.make;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.assignX;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.block;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.param;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.params;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.propX;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.stmt;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
-
-/**
- * Handles transformation for the @Field annotation.
- */
-@GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS)
-public class FieldASTTransformation extends ClassCodeExpressionTransformer implements ASTTransformation, Opcodes {
-
- private static final Class MY_CLASS = Field.class;
- private static final ClassNode MY_TYPE = make(MY_CLASS);
- private static final ClassNode LAZY_TYPE = make(Lazy.class);
- private static final String MY_TYPE_NAME = "@" + MY_TYPE.getNameWithoutPackage();
- private static final ClassNode ASTTRANSFORMCLASS_TYPE = make(GroovyASTTransformationClass.class);
- private static final ClassNode OPTION_TYPE = make(Option.class);
- private SourceUnit sourceUnit;
- private DeclarationExpression candidate;
- private boolean insideScriptBody;
- private String variableName;
- private FieldNode fieldNode;
- private ClosureExpression currentClosure;
- private ConstructorCallExpression currentAIC;
-
- public void visit(ASTNode[] nodes, SourceUnit source) {
- sourceUnit = source;
- if (nodes.length != 2 || !(nodes[0] instanceof AnnotationNode) || !(nodes[1] instanceof AnnotatedNode)) {
- throw new GroovyBugError("Internal error: expecting [AnnotationNode, AnnotatedNode] but got: " + Arrays.asList(nodes));
- }
-
- AnnotatedNode parent = (AnnotatedNode) nodes[1];
- AnnotationNode node = (AnnotationNode) nodes[0];
- if (!MY_TYPE.equals(node.getClassNode())) return;
-
- if (parent instanceof DeclarationExpression) {
- DeclarationExpression de = (DeclarationExpression) parent;
- ClassNode cNode = de.getDeclaringClass();
- if (!cNode.isScript()) {
- addError("Annotation " + MY_TYPE_NAME + " can only be used within a Script.", parent);
- return;
- }
- candidate = de;
- // GROOVY-4548: temp fix to stop CCE until proper support is added
- if (de.isMultipleAssignmentDeclaration()) {
- addError("Annotation " + MY_TYPE_NAME + " not supported with multiple assignment notation.", parent);
- return;
- }
- VariableExpression ve = de.getVariableExpression();
- variableName = ve.getName();
- // set owner null here, it will be updated by addField
- fieldNode = new FieldNode(variableName, ve.getModifiers(), ve.getType(), null, de.getRightExpression());
- fieldNode.setSourcePosition(de);
- cNode.addField(fieldNode);
- // provide setter for CLI Builder purposes unless final
- if (fieldNode.isFinal()) {
- if (!de.getAnnotations(OPTION_TYPE).isEmpty()) {
- addError("Can't have a final field also annotated with @" + OPTION_TYPE.getNameWithoutPackage(), de);
- }
- } else {
- String setterName = "set" + capitalize(variableName);
- cNode.addMethod(setterName, ACC_PUBLIC | ACC_SYNTHETIC, ClassHelper.VOID_TYPE, params(param(ve.getType(), variableName)), ClassNode.EMPTY_ARRAY, block(
- stmt(assignX(propX(varX("this"), variableName), varX(variableName)))
- ));
- }
-
- // GROOVY-4833 : annotations that are not Groovy transforms should be transferred to the generated field
- // GROOVY-6112 : also copy acceptable Groovy transforms
- final List<AnnotationNode> annotations = de.getAnnotations();
- for (AnnotationNode annotation : annotations) {
- // GROOVY-6337 HACK: in case newly created field is @Lazy
- if (annotation.getClassNode().equals(LAZY_TYPE)) {
- LazyASTTransformation.visitField(this, annotation, fieldNode);
- }
- final ClassNode annotationClassNode = annotation.getClassNode();
- if (notTransform(annotationClassNode) || acceptableTransform(annotation)) {
- fieldNode.addAnnotation(annotation);
- }
- }
-
- super.visitClass(cNode);
- // GROOVY-5207 So that Closures can see newly added fields
- // (not super efficient for a very large class with many @Fields but we chose simplicity
- // and understandability of this solution over more complex but efficient alternatives)
- VariableScopeVisitor scopeVisitor = new VariableScopeVisitor(source);
- scopeVisitor.visitClass(cNode);
- }
- }
-
- private static boolean acceptableTransform(AnnotationNode annotation) {
- // TODO also check for phase after sourceUnit.getPhase()? but will be ignored anyway?
- // TODO we should only copy those annotations with FIELD_TARGET but haven't visited annotations
- // and gathered target info at this phase, so we can't do this:
- // return annotation.isTargetAllowed(AnnotationNode.FIELD_TARGET);
- // instead just don't copy ourselves for now
- return !annotation.getClassNode().equals(MY_TYPE);
- }
-
- private static boolean notTransform(ClassNode annotationClassNode) {
- return annotationClassNode.getAnnotations(ASTTRANSFORMCLASS_TYPE).isEmpty();
- }
-
- @Override
- public Expression transform(Expression expr) {
- if (expr == null) return null;
- if (expr instanceof DeclarationExpression) {
- DeclarationExpression de = (DeclarationExpression) expr;
- if (de.getLeftExpression() == candidate.getLeftExpression()) {
- if (insideScriptBody) {
- // TODO make EmptyExpression work
- // partially works but not if only thing in script
- // return EmptyExpression.INSTANCE;
- return new ConstantExpression(null);
- }
- addError("Annotation " + MY_TYPE_NAME + " can only be used within a Script body.", expr);
- return expr;
- }
- } else if (insideScriptBody && expr instanceof VariableExpression && currentClosure != null) {
- VariableExpression ve = (VariableExpression) expr;
- if (ve.getName().equals(variableName)) {
- adjustToClassVar(ve);
- return ve;
- }
- } else if (currentAIC != null && expr instanceof ArgumentListExpression) {
- // if a match is found, the compiler will have already set up aic constructor to hav
- // an argument which isn't needed since we'll be accessing the field; we must undo it
- Expression skip = null;
- List<Expression> origArgList = ((ArgumentListExpression) expr).getExpressions();
- for (int i = 0; i < origArgList.size(); i++) {
- Expression arg = origArgList.get(i);
- if (matchesCandidate(arg)) {
- skip = arg;
- adjustConstructorAndFields(i, currentAIC.getType());
- break;
- }
- }
- if (skip != null) {
- return adjustedArgList(skip, origArgList);
- }
- }
- return expr.transformExpression(this);
- }
-
- private boolean matchesCandidate(Expression arg) {
- return arg instanceof VariableExpression && ((VariableExpression) arg).getAccessedVariable() == candidate.getVariableExpression().getAccessedVariable();
- }
-
- private Expression adjustedArgList(Expression skip, List<Expression> origArgs) {
- List<Expression> newArgs = new ArrayList<Expression>(origArgs.size() - 1);
- for (Expression origArg : origArgs) {
- if (skip != origArg) {
- newArgs.add(origArg);
- }
- }
- return new ArgumentListExpression(newArgs);
- }
-
- private void adjustConstructorAndFields(int skipIndex, ClassNode type) {
- List<ConstructorNode> constructors = type.getDeclaredConstructors();
- if (constructors.size() == 1) {
- ConstructorNode constructor = constructors.get(0);
- Parameter[] params = constructor.getParameters();
- Parameter[] newParams = new Parameter[params.length - 1];
- int to = 0;
- for (int from = 0; from < params.length; from++) {
- if (from != skipIndex) {
- newParams[to++] = params[from];
- }
- }
- type.removeConstructor(constructor);
- // code doesn't mention the removed param at this point, okay to leave as is
- addGeneratedConstructor(type, constructor.getModifiers(), newParams, constructor.getExceptions(), constructor.getCode());
- type.removeField(variableName);
- }
- }
-
- private void adjustToClassVar(VariableExpression expr) {
- // we only need to check the variable name because the Groovy compiler
- // already fails if a variable with the same name already exists in the scope.
- // this means that a closure cannot shadow a class variable
- expr.setAccessedVariable(fieldNode);
- final VariableScope variableScope = currentClosure.getVariableScope();
- final Iterator<Variable> iterator = variableScope.getReferencedLocalVariablesIterator();
- while (iterator.hasNext()) {
- Variable next = iterator.next();
- if (next.getName().equals(variableName)) iterator.remove();
- }
- variableScope.putReferencedClassVariable(fieldNode);
- }
-
- @Override
- public void visitClosureExpression(final ClosureExpression expression) {
- ClosureExpression old = currentClosure;
- currentClosure = expression;
- super.visitClosureExpression(expression);
- currentClosure = old;
- }
-
- @Override
- public void visitConstructorCallExpression(final ConstructorCallExpression cce) {
- if (!insideScriptBody || !cce.isUsingAnonymousInnerClass()) return;
- ConstructorCallExpression old = currentAIC;
- currentAIC = cce;
- Expression newArgs = transform(cce.getArguments());
- if (cce.getArguments() instanceof TupleExpression && newArgs instanceof TupleExpression) {
- List<Expression> argList = ((TupleExpression) cce.getArguments()).getExpressions();
- argList.clear();
- argList.addAll(((TupleExpression) newArgs).getExpressions());
- }
- currentAIC = old;
- }
-
- @Override
- public void visitMethod(MethodNode node) {
- Boolean oldInsideScriptBody = insideScriptBody;
- if (node.isScriptBody()) insideScriptBody = true;
- super.visitMethod(node);
- insideScriptBody = oldInsideScriptBody;
- }
-
- @Override
- public void visitExpressionStatement(ExpressionStatement es) {
- Expression exp = es.getExpression();
- exp.visit(this);
- super.visitExpressionStatement(es);
- }
-
- protected SourceUnit getSourceUnit() {
- return sourceUnit;
- }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.codehaus.groovy.transform;
+
+import groovy.cli.Option;
+import groovy.lang.Lazy;
+import groovy.transform.Field;
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.AnnotatedNode;
+import org.codehaus.groovy.ast.AnnotationNode;
+import org.codehaus.groovy.ast.ClassCodeExpressionTransformer;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.ConstructorNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.Variable;
+import org.codehaus.groovy.ast.VariableScope;
+import org.codehaus.groovy.ast.expr.ArgumentListExpression;
+import org.codehaus.groovy.ast.expr.ClosureExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.DeclarationExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.TupleExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.stmt.ExpressionStatement;
+import org.codehaus.groovy.classgen.VariableScopeVisitor;
+import org.codehaus.groovy.control.CompilePhase;
+import org.codehaus.groovy.control.SourceUnit;
+import org.objectweb.asm.Opcodes;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import static org.apache.groovy.ast.tools.ClassNodeUtils.addGeneratedConstructor;
+import static org.apache.groovy.util.BeanUtils.capitalize;
+import static org.codehaus.groovy.ast.ClassHelper.make;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.assignX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.block;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.param;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.params;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.propX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.stmt;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
+
+/**
+ * Handles transformation for the @Field annotation.
+ */
+@GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS)
+public class FieldASTTransformation extends ClassCodeExpressionTransformer implements ASTTransformation, Opcodes {
+
+ private static final Class MY_CLASS = Field.class;
+ private static final ClassNode MY_TYPE = make(MY_CLASS);
+ private static final ClassNode LAZY_TYPE = make(Lazy.class);
+ private static final String MY_TYPE_NAME = "@" + MY_TYPE.getNameWithoutPackage();
+ private static final ClassNode ASTTRANSFORMCLASS_TYPE = make(GroovyASTTransformationClass.class);
+ private static final ClassNode OPTION_TYPE = make(Option.class);
+ private SourceUnit sourceUnit;
+ private DeclarationExpression candidate;
+ private boolean insideScriptBody;
+ private String variableName;
+ private FieldNode fieldNode;
+ private ClosureExpression currentClosure;
+ private ConstructorCallExpression currentAIC;
+
+ public void visit(ASTNode[] nodes, SourceUnit source) {
+ sourceUnit = source;
+ if (nodes.length != 2 || !(nodes[0] instanceof AnnotationNode) || !(nodes[1] instanceof AnnotatedNode)) {
+ throw new GroovyBugError("Internal error: expecting [AnnotationNode, AnnotatedNode] but got: " + Arrays.asList(nodes));
+ }
+
+ AnnotatedNode parent = (AnnotatedNode) nodes[1];
+ AnnotationNode node = (AnnotationNode) nodes[0];
+ if (!MY_TYPE.equals(node.getClassNode())) return;
+
+ if (parent instanceof DeclarationExpression) {
+ DeclarationExpression de = (DeclarationExpression) parent;
+ ClassNode cNode = de.getDeclaringClass();
+ if (!cNode.isScript()) {
+ addError("Annotation " + MY_TYPE_NAME + " can only be used within a Script.", parent);
+ return;
+ }
+ candidate = de;
+ // GROOVY-4548: temp fix to stop CCE until proper support is added
+ if (de.isMultipleAssignmentDeclaration()) {
+ addError("Annotation " + MY_TYPE_NAME + " not supported with multiple assignment notation.", parent);
+ return;
+ }
+ VariableExpression ve = de.getVariableExpression();
+ variableName = ve.getName();
+ // set owner null here, it will be updated by addField
+ fieldNode = new FieldNode(variableName, ve.getModifiers(), ve.getType(), null, de.getRightExpression());
+ fieldNode.setSourcePosition(de);
+ cNode.addField(fieldNode);
+ // provide setter for CLI Builder purposes unless final
+ if (fieldNode.isFinal()) {
+ if (!de.getAnnotations(OPTION_TYPE).isEmpty()) {
+ addError("Can't have a final field also annotated with @" + OPTION_TYPE.getNameWithoutPackage(), de);
+ }
+ } else {
+ String setterName = "set" + capitalize(variableName);
+ cNode.addMethod(setterName, ACC_PUBLIC | ACC_SYNTHETIC, ClassHelper.VOID_TYPE, params(param(ve.getType(), variableName)), ClassNode.EMPTY_ARRAY, block(
+ stmt(assignX(propX(varX("this"), variableName), varX(variableName)))
+ ));
+ }
+
+ // GROOVY-4833 : annotations that are not Groovy transforms should be transferred to the generated field
+ // GROOVY-6112 : also copy acceptable Groovy transforms
+ final List<AnnotationNode> annotations = de.getAnnotations();
+ for (AnnotationNode annotation : annotations) {
+ // GROOVY-6337 HACK: in case newly created field is @Lazy
+ if (annotation.getClassNode().equals(LAZY_TYPE)) {
+ LazyASTTransformation.visitField(this, annotation, fieldNode);
+ }
+ final ClassNode annotationClassNode = annotation.getClassNode();
+ if (notTransform(annotationClassNode) || acceptableTransform(annotation)) {
+ fieldNode.addAnnotation(annotation);
+ }
+ }
+
+ super.visitClass(cNode);
+ // GROOVY-5207 So that Closures can see newly added fields
+ // (not super efficient for a very large class with many @Fields but we chose simplicity
+ // and understandability of this solution over more complex but efficient alternatives)
+ VariableScopeVisitor scopeVisitor = new VariableScopeVisitor(source);
+ scopeVisitor.visitClass(cNode);
+ }
+ }
+
+ private static boolean acceptableTransform(AnnotationNode annotation) {
+ // TODO also check for phase after sourceUnit.getPhase()? but will be ignored anyway?
+ // TODO we should only copy those annotations with FIELD_TARGET but haven't visited annotations
+ // and gathered target info at this phase, so we can't do this:
+ // return annotation.isTargetAllowed(AnnotationNode.FIELD_TARGET);
+ // instead just don't copy ourselves for now
+ return !annotation.getClassNode().equals(MY_TYPE);
+ }
+
+ private static boolean notTransform(ClassNode annotationClassNode) {
+ return annotationClassNode.getAnnotations(ASTTRANSFORMCLASS_TYPE).isEmpty();
+ }
+
+ @Override
+ public Expression transform(Expression expr) {
+ if (expr == null) return null;
+ if (expr instanceof DeclarationExpression) {
+ DeclarationExpression de = (DeclarationExpression) expr;
+ if (de.getLeftExpression() == candidate.getLeftExpression()) {
+ if (insideScriptBody) {
+ // TODO make EmptyExpression work
+ // partially works but not if only thing in script
+ // return EmptyExpression.INSTANCE;
+ return new ConstantExpression(null);
+ }
+ addError("Annotation " + MY_TYPE_NAME + " can only be used within a Script body.", expr);
+ return expr;
+ }
+ } else if (insideScriptBody && expr instanceof VariableExpression && currentClosure != null) {
+ VariableExpression ve = (VariableExpression) expr;
+ if (ve.getName().equals(variableName)) {
+ adjustToClassVar(ve);
+ return ve;
+ }
+ } else if (currentAIC != null && expr instanceof ArgumentListExpression) {
+ // if a match is found, the compiler will have already set up aic constructor to hav
+ // an argument which isn't needed since we'll be accessing the field; we must undo it
+ Expression skip = null;
+ List<Expression> origArgList = ((ArgumentListExpression) expr).getExpressions();
+ for (int i = 0; i < origArgList.size(); i++) {
+ Expression arg = origArgList.get(i);
+ if (matchesCandidate(arg)) {
+ skip = arg;
+ adjustConstructorAndFields(i, currentAIC.getType());
+ break;
+ }
+ }
+ if (skip != null) {
+ return adjustedArgList(skip, origArgList);
+ }
+ }
+ return expr.transformExpression(this);
+ }
+
+ private boolean matchesCandidate(Expression arg) {
+ return arg instanceof VariableExpression && ((VariableExpression) arg).getAccessedVariable() == candidate.getVariableExpression().getAccessedVariable();
+ }
+
+ private Expression adjustedArgList(Expression skip, List<Expression> origArgs) {
+ List<Expression> newArgs = new ArrayList<Expression>(origArgs.size() - 1);
+ for (Expression origArg : origArgs) {
+ if (skip != origArg) {
+ newArgs.add(origArg);
+ }
+ }
+ return new ArgumentListExpression(newArgs);
+ }
+
+ private void adjustConstructorAndFields(int skipIndex, ClassNode type) {
+ List<ConstructorNode> constructors = type.getDeclaredConstructors();
+ if (constructors.size() == 1) {
+ ConstructorNode constructor = constructors.get(0);
+ Parameter[] params = constructor.getParameters();
+ Parameter[] newParams = new Parameter[params.length - 1];
+ int to = 0;
+ for (int from = 0; from < params.length; from++) {
+ if (from != skipIndex) {
+ newParams[to++] = params[from];
+ }
+ }
+ type.removeConstructor(constructor);
+ // code doesn't mention the removed param at this point, okay to leave as is
+ addGeneratedConstructor(type, constructor.getModifiers(), newParams, constructor.getExceptions(), constructor.getCode());
+ type.removeField(variableName);
+ }
+ }
+
+ private void adjustToClassVar(VariableExpression expr) {
+ // we only need to check the variable name because the Groovy compiler
+ // already fails if a variable with the same name already exists in the scope.
+ // this means that a closure cannot shadow a class variable
+ expr.setAccessedVariable(fieldNode);
+ final VariableScope variableScope = currentClosure.getVariableScope();
+ final Iterator<Variable> iterator = variableScope.getReferencedLocalVariablesIterator();
+ while (iterator.hasNext()) {
+ Variable next = iterator.next();
+ if (next.getName().equals(variableName)) iterator.remove();
+ }
+ variableScope.putReferencedClassVariable(fieldNode);
+ }
+
+ @Override
+ public void visitClosureExpression(final ClosureExpression expression) {
+ ClosureExpression old = currentClosure;
+ currentClosure = expression;
+ super.visitClosureExpression(expression);
+ currentClosure = old;
+ }
+
+ @Override
+ public void visitConstructorCallExpression(final ConstructorCallExpression cce) {
+ if (!insideScriptBody || !cce.isUsingAnonymousInnerClass()) return;
+ ConstructorCallExpression old = currentAIC;
+ currentAIC = cce;
+ Expression newArgs = transform(cce.getArguments());
+ if (cce.getArguments() instanceof TupleExpression && newArgs instanceof TupleExpression) {
+ List<Expression> argList = ((TupleExpression) cce.getArguments()).getExpressions();
+ argList.clear();
+ argList.addAll(((TupleExpression) newArgs).getExpressions());
+ }
+ currentAIC = old;
+ }
+
+ @Override
+ public void visitMethod(MethodNode node) {
+ Boolean oldInsideScriptBody = insideScriptBody;
+ if (node.isScriptBody()) insideScriptBody = true;
+ super.visitMethod(node);
+ insideScriptBody = oldInsideScriptBody;
+ }
+
+ @Override
+ public void visitExpressionStatement(ExpressionStatement es) {
+ Expression exp = es.getExpression();
+ exp.visit(this);
+ super.visitExpressionStatement(es);
+ }
+
+ protected SourceUnit getSourceUnit() {
+ return sourceUnit;
+ }
+}
diff --git a/src/main/java/org/codehaus/groovy/transform/TupleConstructorASTTransformation.java b/src/main/java/org/codehaus/groovy/transform/TupleConstructorASTTransformation.java
index 1748eb6..8dd0f7a 100644
--- a/src/main/java/org/codehaus/groovy/transform/TupleConstructorASTTransformation.java
+++ b/src/main/java/org/codehaus/groovy/transform/TupleConstructorASTTransformation.java
@@ -1,353 +1,353 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.codehaus.groovy.transform;
-
-import groovy.lang.GroovyClassLoader;
-import groovy.transform.CompilationUnitAware;
-import groovy.transform.MapConstructor;
-import groovy.transform.TupleConstructor;
-import groovy.transform.options.PropertyHandler;
-import org.apache.groovy.ast.tools.AnnotatedNodeUtils;
-import org.codehaus.groovy.ast.ASTNode;
-import org.codehaus.groovy.ast.AnnotatedNode;
-import org.codehaus.groovy.ast.AnnotationNode;
-import org.codehaus.groovy.ast.ClassHelper;
-import org.codehaus.groovy.ast.ClassNode;
-import org.codehaus.groovy.ast.ConstructorNode;
-import org.codehaus.groovy.ast.FieldNode;
-import org.codehaus.groovy.ast.Parameter;
-import org.codehaus.groovy.ast.PropertyNode;
-import org.codehaus.groovy.ast.expr.ClosureExpression;
-import org.codehaus.groovy.ast.expr.ConstantExpression;
-import org.codehaus.groovy.ast.expr.Expression;
-import org.codehaus.groovy.ast.expr.VariableExpression;
-import org.codehaus.groovy.ast.stmt.BlockStatement;
-import org.codehaus.groovy.ast.stmt.EmptyStatement;
-import org.codehaus.groovy.ast.stmt.ExpressionStatement;
-import org.codehaus.groovy.ast.stmt.Statement;
-import org.codehaus.groovy.classgen.VariableScopeVisitor;
-import org.codehaus.groovy.control.CompilationUnit;
-import org.codehaus.groovy.control.CompilePhase;
-import org.codehaus.groovy.control.SourceUnit;
-
-import java.lang.annotation.Annotation;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import static org.apache.groovy.ast.tools.AnnotatedNodeUtils.markAsGenerated;
-import static org.apache.groovy.ast.tools.ClassNodeUtils.hasExplicitConstructor;
-import static org.apache.groovy.ast.tools.VisibilityUtils.getVisibility;
-import static org.codehaus.groovy.ast.ClassHelper.make;
-import static org.codehaus.groovy.ast.ClassHelper.makeWithoutCaching;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.args;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.assignS;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.block;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.callX;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.constX;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.copyStatementsWithSuperAdjustment;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.ctorX;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.equalsNullX;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.getAllProperties;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.ifElseS;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.ifS;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.params;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.propX;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.stmt;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.throwS;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
-import static org.codehaus.groovy.transform.ImmutableASTTransformation.makeImmutable;
-
-/**
- * Handles generation of code for the @TupleConstructor annotation.
- */
-@GroovyASTTransformation(phase = CompilePhase.CANONICALIZATION)
-public class TupleConstructorASTTransformation extends AbstractASTTransformation implements CompilationUnitAware {
-
- private CompilationUnit compilationUnit;
- static final Class MY_CLASS = TupleConstructor.class;
- static final ClassNode MY_TYPE = make(MY_CLASS);
- static final String MY_TYPE_NAME = "@" + MY_TYPE.getNameWithoutPackage();
- private static final ClassNode LHMAP_TYPE = makeWithoutCaching(LinkedHashMap.class, false);
- private static final ClassNode CHECK_METHOD_TYPE = make(ImmutableASTTransformation.class);
- private static final Class<? extends Annotation> MAP_CONSTRUCTOR_CLASS = MapConstructor.class;
- private static final Map<Class<?>, Expression> primitivesInitialValues;
-
- static {
- final ConstantExpression zero = constX(0);
- final ConstantExpression zeroDecimal = constX(.0);
- primitivesInitialValues = new HashMap<Class<?>, Expression>();
- primitivesInitialValues.put(int.class, zero);
- primitivesInitialValues.put(long.class, zero);
- primitivesInitialValues.put(short.class, zero);
- primitivesInitialValues.put(byte.class, zero);
- primitivesInitialValues.put(char.class, zero);
- primitivesInitialValues.put(float.class, zeroDecimal);
- primitivesInitialValues.put(double.class, zeroDecimal);
- primitivesInitialValues.put(boolean.class, ConstantExpression.FALSE);
- }
-
- @Override
- public String getAnnotationName() {
- return MY_TYPE_NAME;
- }
-
- public void visit(ASTNode[] nodes, SourceUnit source) {
- init(nodes, source);
- AnnotatedNode parent = (AnnotatedNode) nodes[1];
- AnnotationNode anno = (AnnotationNode) nodes[0];
- if (!MY_TYPE.equals(anno.getClassNode())) return;
-
- if (parent instanceof ClassNode) {
- ClassNode cNode = (ClassNode) parent;
- if (!checkNotInterface(cNode, MY_TYPE_NAME)) return;
- boolean includeFields = memberHasValue(anno, "includeFields", true);
- boolean includeProperties = !memberHasValue(anno, "includeProperties", false);
- boolean includeSuperFields = memberHasValue(anno, "includeSuperFields", true);
- boolean includeSuperProperties = memberHasValue(anno, "includeSuperProperties", true);
- boolean allProperties = memberHasValue(anno, "allProperties", true);
- List<String> excludes = getMemberStringList(anno, "excludes");
- List<String> includes = getMemberStringList(anno, "includes");
- boolean allNames = memberHasValue(anno, "allNames", true);
- if (!checkIncludeExcludeUndefinedAware(anno, excludes, includes, MY_TYPE_NAME)) return;
- if (!checkPropertyList(cNode, includes, "includes", anno, MY_TYPE_NAME, includeFields, includeSuperProperties, allProperties, includeSuperFields, false))
- return;
- if (!checkPropertyList(cNode, excludes, "excludes", anno, MY_TYPE_NAME, includeFields, includeSuperProperties, allProperties, includeSuperFields, false))
- return;
- final GroovyClassLoader classLoader = compilationUnit != null ? compilationUnit.getTransformLoader() : source.getClassLoader();
- final PropertyHandler handler = PropertyHandler.createPropertyHandler(this, classLoader, cNode);
- if (handler == null) return;
- if (!handler.validateAttributes(this, anno)) return;
-
- Expression pre = anno.getMember("pre");
- if (pre != null && !(pre instanceof ClosureExpression)) {
- addError("Expected closure value for annotation parameter 'pre'. Found " + pre, cNode);
- return;
- }
- Expression post = anno.getMember("post");
- if (post != null && !(post instanceof ClosureExpression)) {
- addError("Expected closure value for annotation parameter 'post'. Found " + post, cNode);
- return;
- }
-
- createConstructor(this, anno, cNode, includeFields, includeProperties, includeSuperFields, includeSuperProperties,
- excludes, includes, allNames, allProperties,
- sourceUnit, handler, (ClosureExpression) pre, (ClosureExpression) post);
-
- if (pre != null) {
- anno.setMember("pre", new ClosureExpression(Parameter.EMPTY_ARRAY, EmptyStatement.INSTANCE));
- }
- if (post != null) {
- anno.setMember("post", new ClosureExpression(Parameter.EMPTY_ARRAY, EmptyStatement.INSTANCE));
- }
- }
- }
-
- private static void createConstructor(AbstractASTTransformation xform, AnnotationNode anno, ClassNode cNode, boolean includeFields,
- boolean includeProperties, boolean includeSuperFields, boolean includeSuperProperties,
- List<String> excludes, final List<String> includes, boolean allNames, boolean allProperties,
- SourceUnit sourceUnit, PropertyHandler handler, ClosureExpression pre, ClosureExpression post) {
- boolean callSuper = xform.memberHasValue(anno, "callSuper", true);
- boolean force = xform.memberHasValue(anno, "force", true);
- boolean defaults = !xform.memberHasValue(anno, "defaults", false);
- Set<String> names = new HashSet<String>();
- List<PropertyNode> superList;
- if (includeSuperProperties || includeSuperFields) {
- superList = getAllProperties(names, cNode.getSuperClass(), includeSuperProperties, includeSuperFields, false, allProperties, true, true);
- } else {
- superList = new ArrayList<PropertyNode>();
- }
-
- List<PropertyNode> list = getAllProperties(names, cNode, includeProperties, includeFields, false, allProperties, false, true);
-
- boolean makeImmutable = makeImmutable(cNode);
- boolean specialNamedArgCase = (ImmutableASTTransformation.isSpecialNamedArgCase(list, !defaults) && superList.isEmpty()) ||
- (ImmutableASTTransformation.isSpecialNamedArgCase(superList, !defaults) && list.isEmpty());
-
- // no processing if existing constructors found unless forced or ImmutableBase in play
- if (hasExplicitConstructor(null, cNode) && !force && !makeImmutable) return;
-
- final List<Parameter> params = new ArrayList<Parameter>();
- final List<Expression> superParams = new ArrayList<Expression>();
- final BlockStatement preBody = new BlockStatement();
- boolean superInPre = false;
- if (pre != null) {
- superInPre = copyStatementsWithSuperAdjustment(pre, preBody);
- if (superInPre && callSuper) {
- xform.addError("Error during " + MY_TYPE_NAME + " processing, can't have a super call in 'pre' " +
- "closure and also 'callSuper' enabled", cNode);
- }
- }
-
- final BlockStatement body = new BlockStatement();
-
- List<PropertyNode> tempList = new ArrayList<PropertyNode>(list);
- tempList.addAll(superList);
- if (!handler.validateProperties(xform, body, cNode, tempList)) {
- return;
- }
-
- for (PropertyNode pNode : superList) {
- String name = pNode.getName();
- FieldNode fNode = pNode.getField();
- if (shouldSkipUndefinedAware(name, excludes, includes, allNames)) continue;
- params.add(createParam(fNode, name, defaults, xform, makeImmutable));
- if (callSuper) {
- superParams.add(varX(name));
- } else if (!superInPre && !specialNamedArgCase) {
- Statement propInit = handler.createPropInit(xform, anno, cNode, pNode, null);
- if (propInit != null) {
- body.addStatement(propInit);
- }
- }
- }
- if (callSuper) {
- body.addStatement(stmt(ctorX(ClassNode.SUPER, args(superParams))));
- }
- if (!preBody.isEmpty()) {
- body.addStatements(preBody.getStatements());
- }
... 43220 lines suppressed ...